poj 3648 2-SAT建图+topsort输出结果
其实2-SAT类型题目的类型比较明确,基本模型差不多是对于n组对称的点,通过给出的限制条件建图连边,然后通过缩点和判断冲突来解决问题。要注意的是在topsort输出结果的时候,缩点后建图需要反向连边,然后输出就可以了。2-sat题型差不多。
题意:新娘新郎分别坐在长桌两边,n-1队夫妇来参加婚礼,要求:夫妇不能坐在同一边,通奸关系不能坐在同一边。输出新娘对面的序列。
思路:对称关系:夫妇,限制条件:通奸关系。基础2-sat问题,缩点找冲突topsort输出结果一气呵成。。。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define MAXN 2002 int instack[MAXN],stack[MAXN],fa[MAXN],vis[MAXN],head[MAXN],first[MAXN]; int dfn[MAXN],low[MAXN],in[MAXN],ans[MAXN],que[MAXN]; int a[MAXN][2],b[MAXN][2],flag[MAXN],cf[MAXN],col[MAXN]; int n,m,tot,scnt,time,tt,top,index; struct Edge { int v,next; }edge[MAXN*MAXN],e[MAXN*MAXN]; void addedge(int u,int v) { edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++; } void adde(int u,int v) { e[tt].v=v; e[tt].next=first[u]; first[u]=tt++; } void tarjan(int u) { instack[u]=1; stack[top++]=u; dfn[u]=low[u]=++index; int v; for(int i=head[u];i!=-1;i=edge[i].next) { v=edge[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(low[u]==dfn[u]) { scnt++; do { v=stack[--top]; instack[v]=0; fa[v]=scnt; }while(v!=u); } } void build() { for(int i=0;i<m;i++) //2*n的点 { int t1,t2;char c,v; scanf("%d%c",&t1,&c); scanf("%d%c",&t2,&v); if(c=='h'&&v=='h') { addedge(t1+n,t2); addedge(t2+n,t1); } else if(c=='h'&&v=='w') { addedge(t1+n,t2+n); addedge(t2,t1); } else if(c=='w'&&v=='h') { addedge(t1,t2); addedge(t2+n,t1+n); } else if(c=='w'&&v=='w') { addedge(t1,t2+n); addedge(t2,t1+n); } } addedge(0,n); } void solve() { memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); index=0;scnt=0;top=0; for(int i=0;i<2*n;i++) { if(!dfn[i]) tarjan(i); } } int check() { for(int i=0;i<n;i++) { if(fa[i]==fa[i+n]) //冲突 { return 0; } cf[fa[i]]=fa[i+n]; cf[fa[i+n]]=fa[i]; } return 1; } void topsort() { int head=1,tail=1; for(int i=1;i<=scnt;i++) { if(in[i]==0) { que[tail++]=i; } } int v; while(tail>head) { int u=que[head]; head++; if(col[u]==0) //对于未着色的点x,将x染成红色1,同时将与x矛盾的点cf[x]染成蓝色-1。 { col[u]=1; col[cf[u]]=-1; } for(int i=first[u];i!=-1;i=e[i].next) { v=e[i].v; if(--in[v]==0) { que[tail++]=v; } } } memset(ans,0,sizeof(ans)); for(int i=0;i<n;i++) { if(col[fa[i]]==1) { ans[i]=1; } } for(int i=1;i<n;i++) { if(ans[i]) printf("%dh ",i); else printf("%dw ",i); } printf("\n"); } int main() { while(scanf("%d%d",&n,&m)!=EOF,(n||m)) { memset(head,-1,sizeof(head));tot=0; memset(first,-1,sizeof(first));tt=0; build(); solve(); if(!check())printf("bad luck\n"); else { memset(in,0,sizeof(in)); memset(col,0,sizeof(col)); for(int i=0;i<2*n;i++) { int v; for(int j=head[i];j!=-1;j=edge[j].next) { v=edge[j].v; if(fa[i]!=fa[v]) { adde(fa[v],fa[i]); in[fa[i]]++; } } } topsort(); } } return 0; }