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; }