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