纠结了这么久,终于把传说中的POJ六道 2-SAT 问题(2723,2749,3207,3648,3678,3683)加上 HDU 上面的两道(3062,3715)全部 A 完,真心纠结啊,建图真心恶心,有时候真的不知道那些边该加进去还是不该加进去,说句实话,我觉得 A 完这八题,还是没有学会 2-SAT,还差的很远……= =!
今天以这道题做个小结,时间很紧,暂时转向,待来日再慢慢钻研……
poj3648 Wedding
题意:有一对新人结婚,邀请 n 对夫妇去参加婚礼,入座时有讲究,一个很长的长桌(真心扯淡的题目描述):
1,每对夫妇不能坐在同一边;
2,n 对夫妇中有些人之间有暧昧关系(男女,男男,女女都可以……= =!我快囧死了,出题的好重口),如果两个人有暧昧关系,那么他俩不能同时坐在新娘对面。
也就是说,他俩要么同时和新娘坐在同一边,要么差开分别坐在两边;
我们根据上面的关系建边:
用 A 表示丈夫 A 坐左边,A’ 表示丈夫 A 坐右边,妻子同理用 B 和 B‘ 表示,然后我们设新娘坐在左边,
1,根据上面的1有四种边:(A -> B'),(B -> A'),(A' -> B),(B' -> A)
2,根据上面的2有两种边:假如X 和 Y 有暧昧关系,那么加两条边(X' -> Y),(Y' -> X),因为我们设新娘在左边,所以只有两条边
3,这里是个容易忽略的地方,新娘和新郎之间也要连边(详见代码),具体为什么,我也不太懂,还请哪位神牛赐教,orz 个先
#include<cstdio> #include<cstring> #include<queue> #include<stack> using namespace std; const int N = 2010; struct Edge{ int s,e,next; }edge1[N*N],edge2[N*N]; int n,m,e_num1,vis_num,cnt,head1[N],instack[N],low[N],tim[N],belong[N]; int e_num2,head2[N]; int indeg[2*N],cf[2*N],col[2*N]; void AddEdge1(int a,int b){ edge1[e_num1].s=a; edge1[e_num1].e=b; edge1[e_num1].next=head1[a]; head1[a]=e_num1++; } void AddEdge2(int a,int b){ edge2[e_num2].s=a; edge2[e_num2].e=b; edge2[e_num2].next=head2[a]; head2[a]=e_num2++; } void getmap(){ int i,a,b; char ch1,ch2; e_num1=0; memset(head1,-1,sizeof(head1)); AddEdge1(1,0);//新娘和新郎加两条边,wife' -> wife AddEdge1(2,3);//husband -> husband' for(i=1;i<n;i++){ AddEdge1(4*i,4*i+3); AddEdge1(4*i+3,4*i); AddEdge1(4*i+1,4*i+2); AddEdge1(4*i+2,4*i+1); } for(i=0;i<m;i++){ scanf("%d%c %d%c",&a,&ch1,&b,&ch2); a=(ch1=='w')?(4*a):(4*a+2); b=(ch2=='w')?(4*b):(4*b+2); AddEdge1(a+1,b); AddEdge1(b+1,a); } } stack <int>st; void tarjan(int x){ int i; tim[x]=low[x]=++vis_num; instack[x]=1; st.push(x); for(i=head1[x];i!=-1;i=edge1[i].next){ int u=edge1[i].e; if(tim[u]==-1){ tarjan(u); if(low[x]>low[u])low[x]=low[u]; } else if(instack[u] && low[x]>tim[u])low[x]=tim[u]; } if(low[x]==tim[x]){ cnt++; do{ i=st.top(); st.pop(); instack[i]=0; belong[i]=cnt; }while(i!=x); } } void init(){ vis_num=cnt=0; memset(instack,0,sizeof(instack)); memset(belong,-1,sizeof(belong)); memset(tim,-1,sizeof(tim)); memset(low,0,sizeof(low)); } void out(){ int i; e_num2=0; memset(head2,-1,sizeof(head2)); memset(indeg,0,sizeof(indeg)); for(i=0;i<e_num1;i++){ if(belong[ edge1[i].s ]!=belong[ edge1[i].e ]){ AddEdge2( belong[ edge1[i].e ], belong[ edge1[i].s ] );//反向边 indeg[belong[edge1[i].s]]++; } } queue <int>q; for(i=1;i<=cnt;i++){ if(indeg[i]==0)q.push(i); } memset(col,0,sizeof(col)); while(!q.empty()){ int cur=q.front(); q.pop(); if(col[cur]==0){ col[cur]=1; col[cf[cur]]=-1; } for(i=head2[cur];i!=-1;i=edge2[i].next){ int u=edge2[i].e; if(--indeg[u]==0)q.push(u); } } int blank=0; for(i=1;i<n;i++){ if(blank==0)blank=1; else printf(" "); if(col[ belong[4*i+2] ]==1)printf("%dh",i); else printf("%dw",i); } puts(""); } void solve(){ int i; init(); for(i=0;i<4*n;i++){ if(tim[i]==-1)tarjan(i); } int flag=1; for(i=0;i<2*n;i++){ if(belong[2*i]==belong[2*i+1]){ flag=0;break; } cf[ belong[2*i] ]=belong[2*i+1]; cf[ belong[2*i+1] ]=belong[2*i]; } if(flag==0) printf("bad luck\n"); else out(); } int main() { while(scanf("%d%d",&n,&m),n+m) { getmap(); solve(); } return 0; }