POJ 3648 Wedding 2-sat输出一组解

题目:n对夫妻,参加婚礼,一对夫妻不能坐在桌子的同一侧,m对有性爱关系的*男*女不能坐在桌子的同一侧,新娘新郎必须坐上桌子,输出任意一种新娘对面坐的人的情况。


这个肯定就是2-sat问题,建图时注意建新郎和新娘的边,还有缩点构造新图的时候返向建边,因为当有一条边a->b的时候,表示选a必须选b那么这样我们在选择人的时候,就会有一连串的问题,但是我们直接选b但是他可以不一定选择a,这个新图是个对称的图,因为2-sat问题建图后又很强的对称性,一个最基本的关系是题目给你的m对关系,隐含的就是夫妻关系,他们是排斥的关系,所以要标记这个关系,topsort的时候夫妻一方被选另一方自动到桌子的对面。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<queue>
#include<vector> 
using namespace std;
const int nodes=1000;
const int edges=100000;
struct node
{
	int v,next;
}e[nodes];
int n,m;
int conflict[nodes],dis[nodes],in[nodes];
int head[nodes],cnt;
vector<int>ve[nodes];
stack<int>s;
int low[nodes],dfn[nodes],paint[nodes],instack[nodes],index,col;
void Init()
{
	while(!s.empty()) s.pop();
	for(int i=0;i<=nodes;i++) ve[i].clear();
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(paint,0,sizeof(paint));
	memset(instack,0,sizeof(instack));
	memset(head,-1,sizeof(head));
	index=col=1;
	cnt=0;
}
void add(int a,int b)
{
	e[cnt].v=b;
	e[cnt].next=head[a];
	head[a]=cnt++;
}
int MIN(int a,int b)
{
	if(a<b) return a;
	return b;
}
void tarjan(int u)
{
	dfn[u]=low[u]=index++; 
	instack[u]=1;
	s.push(u);
	for(int i=head[u];i+1;i=e[i].next)
	{
		int v=e[i].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=MIN(low[u],low[v]);
		}
		else if(instack[v])
		{
			low[u]=MIN(low[u],dfn[v]);
		}
	}
	if(dfn[u]==low[u])
	{
		int k=s.top();
		while(k!=u)
		{
			s.pop();
			paint[k]=col;
			instack[k]=0;
			k=s.top();
		}
		s.pop();
		paint[u]=col;
		instack[u]=0;
		col++;
	}
}
void Input()
{
	for(int i=1;i<=m;i++)
	{
		int a,b;
		int aa,bb;
		char ch1,ch2;
		scanf("%d%c %d%c",&a,&ch1,&b,&ch2);
		if(ch1=='h')
		{
			a=a+n;
			aa=a-n;
		}
		else
		{
			aa=a+n;
		}
		if(ch2=='h')
		{
			b=b+n;
			bb=b-n;
		}
		else 
		{
			bb=b+n;
		}
		add(a,bb);
		add(b,aa);
	}
	add(0,n);
}
void topsort()
{
	queue<int>q;
	while(!q.empty()) q.pop();
	for(int i=0;i<2*n;i++)
	{
		if(!in[i])
		q.push(i);
	}
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		if(!dis[u])
		{
			dis[u]=1;
			dis[conflict[u]]=2;
		}
		for(int i=0;i<ve[u].size();i++)
		{
			int v=ve[u][i];
			if(--in[v]==0)
			{
				q.push(v);
			}
		}
	}
}
void Output()
{
	memset(conflict,0,sizeof(conflict));
	memset(dis,0,sizeof(dis));
	memset(in,0,sizeof(in));
	for(int i=0;i<n;i++)
	{
		conflict[paint[i]]=paint[i+n];
		conflict[paint[i+n]]=paint[i];
	}
	for(int i=0;i<2*n;i++)
	{
		for(int j=head[i];j+1;j=e[j].next)
		{
			int v=e[j].v;
			if(paint[i]!=paint[v])
			{
				ve[paint[v]].push_back(paint[i]);
				in[paint[i]];
			}
		}
	}
	topsort();
	for(int i=1;i<n;i++)
	{
		if(i!=1) printf(" ");
		if(dis[paint[i]]==dis[paint[0]])
		{
			printf("%dw",i);
		}
		else printf("%dh",i);
	}
} 
void treatment()
{
	int mark=1;
	for(int i=0;i<2*n;i++)
	{
		if(!dfn[i]) tarjan(i);
	}
	col--;
	for(int i=0;i<n;i++)
	{
		if(paint[i]==paint[i+n])
		{
			mark=0;
			break;
		}
	}
	if(!mark) printf("bad luck\n");
	else Output();
}
int main()
{
	while(~scanf("%d%d",&n,&m),n+m)
	{
		Init();
		Input();
		treatment();
	}
	return 0;
} 

你可能感兴趣的:(POJ 3648 Wedding 2-sat输出一组解)