http://poj.org/problem?id=3648
新娘和新郎 和其他夫妇 一共n对 每对夫妇不能做在同一侧 而且有奸情的人两个人(男女 男男 女女 出题人口味好重呀)不能同时坐在新娘的对面
2-SAT
限制条件 n对夫妇一共2×n个人 0--n-1 是新娘 n--2×n-1是对应新郎 染色时 1代表和新娘同侧 -1代表不同侧
首先 新娘必须和新娘同侧2×n-->0 新郎必须和新娘对面n-->n+2×n
其他夫妇必须异侧
有奸情的有一个在新娘对面 另一个一定和新娘同侧
代码及其注释:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#define LL long long
using namespace std;
const int N=150;
int head1[N],I1;
int head2[N],I2;
struct ss
{
int j,next;
}side1[N*N],side2[N*N];
int low[N],dfn[N],f[N],deep;
bool in[N],visited[N];
int num[N],sele[N];
stack<int>st;
queue<int>qt;
vector<int>vt[N];
void build1(int x,int y)
{
side1[I1].j=y;
side1[I1].next=head1[x];
head1[x]=I1++;
}
void build2(int x,int y)
{
side2[I2].j=y;
side2[I2].next=head2[x];
head2[x]=I2++;
}
void Tarjan(int x)//将环缩点
{
visited[x]=true;
in[x]=true;
st.push(x);
low[x]=dfn[x]=deep++;
for(int t=head1[x];t!=-1;t=side1[t].next)
{
int k=side1[t].j;
if(visited[k]==false)
{
Tarjan(k);
low[x]=min(low[x],low[k]);
}else if(in[k]==true)
{
low[x]=min(low[x],dfn[k]);
}
}
if(low[x]==dfn[x])
{
while(st.top()!=x)
{
int k=st.top();
st.pop();
in[k]=false;
f[k]=x;
vt[x].push_back(k);
}
int k=st.top();
st.pop();
in[k]=false;
f[k]=x;
}
}
void Fsearch(int x)//建立新图
{
for(int t=head1[x];t!=-1;t=side1[t].next)
{
int k=side1[t].j;
if(f[x]!=f[k])
{
build2(f[k],f[x]);
++num[f[x]];
}
}
}
void color(int x,int K)//染色 本环和相对的环 染不同色
{
x=f[x];
sele[x]=1;
for(unsigned int i=0;i<vt[x].size();++i)
{sele[vt[x][i]]=1;}
x=(x<K)?x+K:x-K;
x=f[x];
sele[x]=-1;
for(unsigned int i=0;i<vt[x].size();++i)
{sele[vt[x][i]]=-1;}
}
void subnum(int x)//拓扑 减边
{
for(int t=head2[x];t!=-1;t=side2[t].next)
{
int k=side2[t].j;
--num[f[k]];
if(num[f[k]]==0)
qt.push(f[k]);
}
}
int main()
{
//freopen("data.txt","r",stdin);
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
memset(head1,-1,sizeof(head1));
I1=0;
build1(0+2*n,0);//新娘和自己同侧
build1(n,n+2*n);//新郎对面
for(int i=1;i<n;++i)
{
build1(i,i+n+2*n);//其他夫妇 不能同侧
build1(i+n,i+2*n);
build1(i+2*n,i+n);
build1(i+n+2*n,i);
}
for(int i=0;i<m;++i)
{
int k1,k2;
char c1,c2;
scanf("%d%c%d%c",&k1,&c1,&k2,&c2);
if(c1=='h')
k1+=n;
if(c2=='h')
k2+=n;
build1(k1+2*n,k2);//有一个在新娘对面 另一个一定在新娘同侧
build1(k2+2*n,k1);
}
while(!st.empty())
st.pop();
for(int i=0;i<4*n;++i)
{vt[i].clear();f[i]=i;}
memset(in,false,sizeof(in));
memset(visited,false,sizeof(visited));
deep=0;
int l;
for(l=0;l<4*n;++l)
{
if(visited[l]==false)
Tarjan(l);
if(l<2*n&&f[l]==f[l+2*n])
break;
}
if(l<2*n)
printf("bad luck\n");
else
{
memset(head2,-1,sizeof(head2));
memset(num,0,sizeof(num));
I2=0;
for(int i=0;i<4*n;++i)//将缩点 建新边
Fsearch(i);
for(int i=0;i<4*n;++i)
if(f[i]==i&&num[i]==0)//拓扑中 为0的入队列
qt.push(i);
memset(sele,0,sizeof(sele));
while(!qt.empty())
{
int k=qt.front();
qt.pop();
if(sele[k]==0)//染色
color(k,2*n);
subnum(k);
}
for(int i=1;i<n;++i)
{
if(sele[i]==1)
printf("%dw",i);
else
printf("%dh",i);
if(i<n-1)
printf(" ");
else
printf("\n");
}
}
}
return 0;
}
浙公网安备 33010602011771号