poj 3648 Wedding 2-sat
2014-12-11 19:11
288 查看
题意:
给n对***安排座位,每对***相对而坐,给出m对特殊关系,有特殊关系的人不能一起坐在新娘对面。
分析:
2-sat+输出解。
代码:
上面的算法用tarjan算法求强连通分量,求完后还要求DAG,比较繁琐,相比之下,下面的做法用Kosaraju算法求强联通分量,因为Kosaraju的结果是拓扑有序的(很有用的性质),所以可以省略求DAG的步骤,代码量减少了50%,清晰简洁不少:
给n对***安排座位,每对***相对而坐,给出m对特殊关系,有特殊关系的人不能一起坐在新娘对面。
分析:
2-sat+输出解。
代码:
#include <iostream> #include <stack> #include <vector> #include <queue> using namespace std; const int maxN=1024; const int maxM=42000; int e,e1,n,m,t,ecnt; int head[maxN],head1[maxN],ins[maxN],low[maxN],dfn[maxN]; int sol[maxN],belong[maxN],d[maxN],ans[maxN]; int cf[maxN],color[maxN],vis[maxN]; stack<int> s; queue<int> Q; struct Edge { int u,v,next; }edge[maxM],edge1[maxM]; void addegde(int u,int v) { edge[e].u=u; edge[e].v=v; edge[e].next=head[u]; head[u]=e++; } void addegde1(int u,int v) { edge1[e1].u=u; edge1[e1].v=v; edge1[e1].next=head1[u]; head1[u]=e1++; } void dfs(int x) { low[x]=dfn[x]=++t; s.push(x); ins[x]=1; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!dfn[v]){ dfs(v); low[x]=min(low[x],low[v]); }else if(ins[v]==1) low[x]=min(low[x],dfn[v]); } if(dfn[x]==low[x]){ ++ecnt; int k; do{ k=s.top(); s.pop(); ins[k]=0; belong[k]=ecnt; }while(k!=x); } } void build() { int i; e1=0; memset(head1,-1,sizeof(head1)); memset(d,0,sizeof(d)); memset(color,0,sizeof(color)); for(i=0;i<e;++i) if(belong[edge[i].u]!=belong[edge[i].v]){ addegde1(belong[edge[i].v],belong[edge[i].u]); ++d[belong[edge[i].u]]; } while(!Q.empty()) Q.pop(); memset(vis,0,sizeof(vis)); for(i=1;i<=ecnt;++i) if(d[i]==0) Q.push(i); while(!Q.empty()){ int u=Q.front(); vis[u]=1; Q.pop(); if(color[u]==0){ color[u]=1; color[cf[u]]=-1; } for(int i=head1[u];i!=-1;i=edge1[i].next){ int v=edge1[i].v; --d[v]; if(d[v]==0&&vis[v]==0) Q.push(v); } } memset(ans,0,sizeof(ans)); for(i=0;i<n;++i){ if(color[belong[2*i+1]]==1) ans[i]=1; } } int two_sat() { memset(ins,0,sizeof(ins)); memset(dfn,0,sizeof(dfn)); while(!s.empty()) s.pop(); int i; t=0,ecnt=0; for(i=0;i<2*n;++i) if(!dfn[i]) dfs(i); for(i=0;i<n;++i) if(belong[2*i]==belong[2*i+1]) return 0; else{ cf[belong[2*i]]=belong[2*i+1]; cf[belong[2*i+1]]=belong[2*i]; } build(); return 1; } int main() { int i; while(scanf("%d%d",&n,&m)==2){ if(n==0&&m==0) break; char c1,c2; int d1,d2,x,y; e=0; memset(head,-1,sizeof(head)); for(i=0;i<m;++i){ scanf("%d%c%d%c",&d1,&c1,&d2,&c2); if(c1=='h') x=2*d1+1; else x=2*d1; if(c2=='h') y=2*d2+1; else y=2*d2; addegde(x,y^1); addegde(y,x^1); } addegde(0,1); if(two_sat()==0) printf("bad luck\n"); else{ for(i=1;i<n;++i){ if(ans[i]==1) printf("%dw ",i); else printf("%dh ",i); } printf("\n"); } } return 0; }
上面的算法用tarjan算法求强连通分量,求完后还要求DAG,比较繁琐,相比之下,下面的做法用Kosaraju算法求强联通分量,因为Kosaraju的结果是拓扑有序的(很有用的性质),所以可以省略求DAG的步骤,代码量减少了50%,清晰简洁不少:
#include <iostream> #include <vector> using namespace std; const int maxN=200; vector<int> g[maxN],ng[maxN]; int n,m,cnt,scc,ans[maxN],vis[maxN],dfn[maxN],cf[maxN],color[maxN]; void addegde(int u,int v) { g[u].push_back(v); ng[v].push_back(u); } void dfs(int k) { vis[k]=1; for(int i=g[k].size()-1;i>=0;--i) if(!vis[g[k][i]]) dfs(g[k][i]); dfn[++cnt]=k; } void ndfs(int k) { vis[k]=scc; for(int i=ng[k].size()-1;i>=0;--i) if(!vis[ng[k][i]]) ndfs(ng[k][i]); } void kosaraju() { memset(vis,0,sizeof(vis)); cnt=0; for(int i=0;i<2*n;++i) if(!vis[i]) dfs(i); memset(vis,0,sizeof(vis)); scc=0; for(int i=2*n;i>=1;--i) if(!vis[dfn[i]]){ ++scc; ndfs(dfn[i]); } } int two_sat() { int i; kosaraju(); for(i=0;i<n;++i) if(vis[2*i]==vis[2*i+1]) return 0; else{ cf[vis[2*i]]=vis[2*i+1]; cf[vis[2*i+1]]=vis[2*i]; } memset(color,0,sizeof(color)); for(i=scc;i>=1;--i) if(color[i]==0){ color[i]=1; color[cf[i]]=-1; } memset(ans,0,sizeof(ans)); for(i=0;i<n;++i) if(color[vis[2*i+1]]==1) ans[i]=1; return 1; } int main() { int i; while(scanf("%d%d",&n,&m)==2){ if(n==0&&m==0) break; char c1,c2; int d1,d2,x,y; for(i=0;i<2*n;++i) g[i].clear(),ng[i].clear(); for(i=0;i<m;++i){ scanf("%d%c%d%c",&d1,&c1,&d2,&c2); if(c1=='h') x=2*d1+1; else x=2*d1; if(c2=='h') y=2*d2+1; else y=2*d2; addegde(x,y^1); addegde(y,x^1); } addegde(0,1); if(two_sat()==0) printf("bad luck\n"); else{ for(i=1;i<n;++i){ if(ans[i]==1) printf("%dw ",i); else printf("%dh ",i); } printf("\n"); } } return 0; }
相关文章推荐
- poj 3648 wedding(2-sat 拓扑排序输出方案)
- POJ 3648 Wedding 2-SAT
- POJ 3648 - Wedding...阅读理解.题意坑爹.2-sat..细节注意
- POJ-3648 Wedding 2sat
- poj 3648 Wedding(2-sat)
- poj 3648 Wedding 2-SAT
- poj 3648 Wedding 2-SAT
- POJ 3648 Wedding(2-SAT)
- poj 3648 Wedding 2_SAT
- POJ 3648-Wedding(2-SAT)
- POJ_3648 Wedding 2-Sat
- 【POJ】3648 Wedding 2-sat
- poj 3648 Wedding(2-sat 求解)
- poj 3648 Wedding(2-SAT)
- poj 3648 Wedding(2-sat--拓扑排序输出可行解)
- POJ-3648-Wedding(2-sat)
- Poj 3648 Wedding【2-Sat--------Tarjan强连通+缩点染色+拓扑排序】
- [2-sat][topsort输出解] POJ 3648 Wedding
- Poj 3648 Wedding (2-sat 输出方案)
- POJ 3648 Wedding (2-SAT,经典)