您的位置:首页 > 其它

poj 3648 Wedding 2-sat

2014-12-11 19:11 288 查看
题意:

给n对***安排座位,每对***相对而坐,给出m对特殊关系,有特殊关系的人不能一起坐在新娘对面。

分析:

2-sat+输出解。

代码:

#include <iostream>
#include <stack>
#include <vector>
#include <queue>
using namespace std;
const int maxN=1024;
const int maxM=42000;
int e,e1,n,m,t,ecnt;
int head[maxN],head1[maxN],ins[maxN],low[maxN],dfn[maxN];
int sol[maxN],belong[maxN],d[maxN],ans[maxN];
int cf[maxN],color[maxN],vis[maxN];

stack<int> s;
queue<int> Q;

struct Edge
{
	int u,v,next;
}edge[maxM],edge1[maxM];

void addegde(int u,int v)
{
	edge[e].u=u;
	edge[e].v=v;
	edge[e].next=head[u];
	head[u]=e++;		
}

void addegde1(int u,int v)
{
	edge1[e1].u=u;
	edge1[e1].v=v;
	edge1[e1].next=head1[u];
	head1[u]=e1++;	
}
void dfs(int x)
{
	low[x]=dfn[x]=++t;	
	s.push(x);
	ins[x]=1;
	for(int i=head[x];i!=-1;i=edge[i].next){
		int v=edge[i].v;
		if(!dfn[v]){
			dfs(v);
			low[x]=min(low[x],low[v]);
		}else if(ins[v]==1)
			low[x]=min(low[x],dfn[v]);
	} 
	if(dfn[x]==low[x]){
		++ecnt;		
		int k;
		do{
			k=s.top();
			s.pop();
			ins[k]=0;
			belong[k]=ecnt;
		}while(k!=x);
	}
}

void build()
{
	int i;
	e1=0;
	memset(head1,-1,sizeof(head1));
	memset(d,0,sizeof(d));
	memset(color,0,sizeof(color));
	for(i=0;i<e;++i)
		if(belong[edge[i].u]!=belong[edge[i].v]){
			addegde1(belong[edge[i].v],belong[edge[i].u]);
			++d[belong[edge[i].u]];
		}
	while(!Q.empty()) Q.pop();
	memset(vis,0,sizeof(vis));
	for(i=1;i<=ecnt;++i)
		if(d[i]==0)
			Q.push(i);
	while(!Q.empty()){
		int u=Q.front();
		vis[u]=1;
		Q.pop();
		if(color[u]==0){
			color[u]=1;
			color[cf[u]]=-1;
		}
		for(int i=head1[u];i!=-1;i=edge1[i].next){
			int v=edge1[i].v;
			--d[v];
			if(d[v]==0&&vis[v]==0)
				Q.push(v);
		}
	}					
	memset(ans,0,sizeof(ans));	
	for(i=0;i<n;++i){
		if(color[belong[2*i+1]]==1)
			ans[i]=1;
	}

}

int two_sat()
{
	memset(ins,0,sizeof(ins));	
	memset(dfn,0,sizeof(dfn)); 
	while(!s.empty()) s.pop();
	int i;
	t=0,ecnt=0;
	for(i=0;i<2*n;++i)
		if(!dfn[i])
			dfs(i);
	for(i=0;i<n;++i)
		if(belong[2*i]==belong[2*i+1])
			return 0;
		else{
			cf[belong[2*i]]=belong[2*i+1];
			cf[belong[2*i+1]]=belong[2*i]; 
		}	
	build();
	return 1;
}

int main()
{
	int i;
	while(scanf("%d%d",&n,&m)==2){
		if(n==0&&m==0) break;
		char c1,c2;
		int d1,d2,x,y;
		e=0;
		memset(head,-1,sizeof(head));
		for(i=0;i<m;++i){
			scanf("%d%c%d%c",&d1,&c1,&d2,&c2);	
			if(c1=='h')
				x=2*d1+1;
			else
				x=2*d1;
			if(c2=='h')
				y=2*d2+1;
			else
				y=2*d2;
			addegde(x,y^1);
			addegde(y,x^1);	
		}
		addegde(0,1);
		if(two_sat()==0)
			printf("bad luck\n");
		else{
			for(i=1;i<n;++i){
				if(ans[i]==1)
					printf("%dw ",i);
				else
					printf("%dh ",i);
			}
			printf("\n");
		}
	}	
	return 0;	
}


上面的算法用tarjan算法求强连通分量,求完后还要求DAG,比较繁琐,相比之下,下面的做法用Kosaraju算法求强联通分量,因为Kosaraju的结果是拓扑有序的(很有用的性质),所以可以省略求DAG的步骤,代码量减少了50%,清晰简洁不少:

#include <iostream>
#include <vector>
using namespace std;
const int maxN=200;
vector<int> g[maxN],ng[maxN];
int n,m,cnt,scc,ans[maxN],vis[maxN],dfn[maxN],cf[maxN],color[maxN];

void addegde(int u,int v)
{
	g[u].push_back(v);
	ng[v].push_back(u);		
}

void dfs(int k)
{
	vis[k]=1;
	for(int i=g[k].size()-1;i>=0;--i)
		if(!vis[g[k][i]])
			dfs(g[k][i]);
	dfn[++cnt]=k;
}

void ndfs(int k)
{
	vis[k]=scc;
	for(int i=ng[k].size()-1;i>=0;--i)
		if(!vis[ng[k][i]])
			ndfs(ng[k][i]);	
}
void kosaraju()
{
	memset(vis,0,sizeof(vis));
	cnt=0;
	for(int i=0;i<2*n;++i)
		if(!vis[i])
			dfs(i);	
	memset(vis,0,sizeof(vis));
	scc=0;
	for(int i=2*n;i>=1;--i)
		if(!vis[dfn[i]]){
			++scc;
			ndfs(dfn[i]);
		}
}

int two_sat()
{
	int i;
	kosaraju();
 	for(i=0;i<n;++i)
 		if(vis[2*i]==vis[2*i+1])
		 	return 0;			
		else{
			cf[vis[2*i]]=vis[2*i+1];
			cf[vis[2*i+1]]=vis[2*i];			
		}
	memset(color,0,sizeof(color));
	for(i=scc;i>=1;--i)
		if(color[i]==0){
			color[i]=1;
			color[cf[i]]=-1;
		}
	memset(ans,0,sizeof(ans));
	for(i=0;i<n;++i)
		if(color[vis[2*i+1]]==1)
			ans[i]=1;	
	return 1;
}

int main()
{
	int i;
	while(scanf("%d%d",&n,&m)==2){
		if(n==0&&m==0) break;
		char c1,c2;
		int d1,d2,x,y;
		for(i=0;i<2*n;++i) g[i].clear(),ng[i].clear(); 
		for(i=0;i<m;++i){
			scanf("%d%c%d%c",&d1,&c1,&d2,&c2);	
			if(c1=='h')
				x=2*d1+1;
			else
				x=2*d1;
			if(c2=='h')
				y=2*d2+1;
			else
				y=2*d2;
			addegde(x,y^1);
			addegde(y,x^1);	
		}
		addegde(0,1);
		if(two_sat()==0)
			printf("bad luck\n");
		else{
			for(i=1;i<n;++i){
				if(ans[i]==1)
					printf("%dw ",i);
				else
					printf("%dh ",i);
			}
			printf("\n");
		}
	}	
	return 0;	
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: