【bzoj1194】 HNOI2006—潘多拉的盒子

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;
}
原文地址:https://www.cnblogs.com/MashiroSky/p/6404137.html