【bzoj1194】 HNOI2006—潘多拉的盒子

时间:2022-01-01 04:07:11

http://www.lydsy.com/JudgeOnline/problem.php?id=1194 (题目链接)

题意

  给出S个自动机,如果一个自动机u的所有状态是另一个自动机v的状态的子集,那么我们连一条有向边(u,v),问最长链。(事实上还要求方案)

Solution

  神题。如果我们知道了包含关系,那么对于不需要求方案的bzoj上的,我们只需要Floyd一遍就可以了,求方案的其实也只需要topsort后dp。

  具体细节:http://blog.csdn.net/ww140142/article/details/48008157

代码

// bzoj1194
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf (1ll<<30)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=60;
int f[maxn][maxn],vis[maxn][maxn],S; struct statu {int x,y;};
struct data {
int n,m;
int t[maxn][2],p[maxn];
}a[maxn]; bool bfs(data u,data v) { //u包含v
memset(vis,0,sizeof(vis));
queue<statu> q;
q.push((statu){0,0});vis[0][0]=1;
while (!q.empty()) {
statu x=q.front();q.pop();
if (!u.p[x.x] && v.p[x.y]) return 0;
for (int i=0;i<=1;i++) {
int xx=u.t[x.x][i],yy=v.t[x.y][i];
if (!vis[xx][yy]) q.push((statu){xx,yy}),vis[xx][yy]=1;
}
}
return 1;
}
void Floyd() {
for (int k=0;k<S;k++)
for (int i=0;i<S;i++)
for (int j=0;j<S;j++)
if (i!=j && j!=k && i!=k && f[i][k] && f[k][j])
f[i][j]=max(f[i][j],f[i][k]+f[k][j]);
}
int main() {
scanf("%d",&S);
for (int i=0;i<S;i++) {
scanf("%d%d",&a[i].n,&a[i].m);
for (int x,j=1;j<=a[i].m;j++) scanf("%d",&x),a[i].p[x]=1;
for (int j=0;j<a[i].n;j++)
scanf("%d%d",&a[i].t[j][0],&a[i].t[j][1]);
}
for (int i=0;i<S;i++)
for (int j=0;j<S;j++)
if (i!=j && bfs(a[i],a[j]))
if (i<j || !f[j][i]) f[i][j]=1;
Floyd();
int ans=0;
for (int i=0;i<S;i++)
for (int j=0;j<S;j++) if (i!=j) ans=max(ans,f[i][j]);
printf("%d",ans+1);
return 0;
}