poj 3684(2-sat解输出)拓扑+染色
2012-07-12 13:22
134 查看
http://blog.csdn.net/sdj222555/article/details/7718821 回头再看看,还不是很理解,染色 转: 这题的题意稍不留神就会看错,注意那个keep ...from 是啥意思 所以新娘看不见本排的情况,只能看见对面,要求不能看见不正常关系的一对。并且夫妇不能同时坐在一边。 很明显的模型了,由于新娘看的是对面的情况,所以就需要对新娘对面的人来分析建图,n对夫妇是2 *n个点, n对夫妇每对夫妇只能挑一个到新娘对面坐下,这很符合2-sat的初始的状态。然后又有一些不正常关系,就需要分别建图了。 并且初始时应该是丈夫坐在新娘对面的,新娘编号为0,丈夫为1的话,必须加一条(0,1)的边表示丈夫必然坐在对面。 建完图后缩点,判断有没有解后,需要建新图,即缩点后的逆序图,然后进行拓扑排序,染色。 注意,我们需要将每对***两者各自代表的强连通分量映射起来,表示这两个强连通分量是不可以在一块的。这样在新图染色的时候,每染到一个点,根据刚才存储的映射将对应的点染为别的颜色。最后输出解时,找跟新娘同色的解即为和新娘同一排的人。 #include <iostream> #include <iostream> #include <cstring> #include <vector> #include <stack> #include <cstdio> #include <queue> using namespace std; const int N=6000; int n,m; int dfn ; int low ; int cnt; int tmp; int fa ; int instack ; stack<int>mystack; vector<int>grap ; vector<int>new_G ; int cf ; int indegree ; int map ; int col ; queue<int>q; void init() { cnt=tmp=0; while(!q.empty()) q.pop(); while(!mystack.empty()) mystack.pop(); for(int i=0;i<2*n;i++) grap[i].clear(),new_G[i].clear(); memset(indegree,0,sizeof(indegree)); memset(col,0,sizeof(col)); memset(cf,0,sizeof(cf)); memset(instack,0,sizeof(instack)); memset(dfn,0,sizeof(dfn)); } void built() { init(); int x,y; char c1,c2; int a0,a1,b0,b1; while(m--) { scanf("%d%c %d%c", &x, &c1, &y, &c2); if(c1 == 'h') a0 = 2 * x, a1 = 2 * x + 1; else a0 = 2 * x + 1, a1 = 2 * x; if(c2 == 'h') b0 = 2 * y, b1 = 2 * y + 1; else b0 = 2 * y + 1, b1 = 2 * y; grap[a1].push_back(b0); grap[b1].push_back(a0); } grap[0].push_back(1); } void tarjan(int u) { dfn[u] = low[u] = ++tmp; instack[u] = 1; mystack.push(u); int size = grap[u].size(), v; for(int i = 0; i < size; i++) { v = grap[u][i]; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if(instack[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { cnt++; do { v = mystack.top(); mystack.pop(); instack[v] = 0; fa[v] = cnt; }while(v != u); } } void rebuilt() { for(int u = 0; u < 2 * n; u++) { int size = grap[u].size(); for(int i = 0; i < size; i++) { int v = grap[u][i]; if(fa[u] != fa[v]) new_G[fa[v]].push_back(fa[u]), indegree[fa[u]]++; } } } void topsort() { for(int i = 1; i <= cnt; i++) if(indegree[i] == 0) q.push(i); while(!q.empty()) { int u = q.front(); q.pop(); int size = new_G[u].size(); if(!col[u]) col[u] = 1, col[cf[u]] = 2; for(int i = 0; i < size; i++) { int v = new_G[u][i]; indegree[v]--; if(indegree[v] == 0) q.push(v); } } } void solve() { for(int i = 0; i < 2 * n; i++) if(!dfn[i]) tarjan(i); for(int i = 0; i < n; i++) if(fa[2 * i] == fa[2 * i + 1]) { puts("bad luck"); return; } else cf[fa[2 * i]] = fa[2 * i + 1], cf[fa[2 * i + 1]] = fa[2 * i]; rebuilt(); topsort(); for(int i = 2; i < 2 * n; i += 2) if(col[fa[i]] == col[fa[0]]) printf("%d%c ", i / 2, 'w'); else printf("%d%c ", i / 2, 'h'); printf("\n"); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; built(); solve(); } return 0; }
相关文章推荐
- Light oj 1251 - Forming the Council 【2-sat】【判断是否存在可行解 + 反向拓扑输出可行解】
- poj 3683 Priest John's Busiest Day 【2-sat 经典建图输出一组解】【有向图tarjan + 反向拓扑 + 染色】
- Light oj 1251 - Forming the Council 【2-sat】【推断是否存在可行解 + 反向拓扑输出可行解】
- POJ 3648 2-sat 输出解
- poj3683Priest John's Busiest Day【2-sat二选一输出】
- 逃生 HDU杭电4857 【反向拓扑+优先队列+反向输出】
- 利用飞- buck转换器拓扑生成孤立的输出
- gym 100430【2-SAT+输出方案】
- Hdu 1814 Peaceful Commission(2-sat+输出字典序最小方案)
- 2-sat 输出任意一组可行解&拓扑排序+缩点 poj3683
- poj 3648 Wedding 【2-sat 经典建图 输出一组可行解 好题】 【tarjan求SCC + 缩点 + 拓扑排序 + 染色】
- 【POJ3683】Priest John's Busiest Day (2-sat输出任意解)
- 2-SAT问题的方案输出
- Light OJ 1407 - Explosion 【2-sat之 3布尔变量的处理 — 枚举所有状态判断是否存在可行解 + 反向输出可行解】【好题】
- UVALive 3713 Astronauts(2-sat+输出任意路径)
- POJ 3683 2-SAT +输出方案
- 使用DFS进行拓扑排序,如果可以完成的话,输出路径
- HDU1814.Peaceful Commission——2-sat输出字典序最小的解
- POJ 3683 2-sat 输出解
- POJ 3683 Priest John's Busiest Day(2-SAT + 拓扑输出方案)