POJ 3648-Wedding(2-SAT)
来源:互联网 发布:陕西大数据集团 编辑:程序博客网 时间:2024/05/17 07:27
【题目大意】很多对夫妇参加一对新人的婚礼。分别做在长桌子的两侧。新郎、新娘分别坐两侧,新娘只能看到她对面的人。新娘不想看到她对面有夫妇。
而且有一些人是有通奸关系的(男的和男的有,女的和男的、女的和女的都可能有,而且新郎也可能和别人有通奸关系),新娘不想看到有通奸关系一对人。
也就是有通奸关系的不能一起坐在新娘对面。
输入是:_n对夫妇(包括新郎新娘在女的,编号为0-(n-1),新郎、新娘那一对的编号为0),_m对通奸关系。
接下来_m行有通奸关系的。h表示男的,w表是女的,3w 5h即表示第三对夫妇的女的和第五对夫妇的男的有不寻常关系
思路:要转化成一个比较好的2-sat, 一开始我想的是,每个人都可以坐在右面也可以坐在左面,这个就是个2-sat, 那么夫妇, 通奸的人都是限制关系。。这样也可以只不过有点麻烦, 这样建图看这个大神的吧 ->点击打开链接
题意:
有一对新人结婚,n-1对夫妇去参加婚礼.有一个很长的座子,新娘与新郎坐在座子的两边(相反).接下来n-1对夫妇就坐,其中任何一对夫妇都不能坐在同一边,且(有一些人有奸情)这些有奸情的两个人不能同时坐在新娘对面.(只能分开做,或者都坐到新娘一边去)。对于每个输入实例,输出应该坐在新娘同一边的人编号。
分析:
由于有n对夫妇(0号表示新婚夫妻).所以我们这里用0表示第0对的妻子,1表示第0对的丈夫. 2*i表示第i对的夫人,2*i+1表示第i对的丈夫.一共就有2*n个人了.
然后对于每个人来说,把他分成两个节点,如果该人在做左边就mark[i*2],如果该人坐右边就mark[i*2+1].
我令新娘直接坐左边即第0个人mark[0]=true,新郎直接坐右边即第1个人mark[1*2+1]=true.
然后对于每对夫妻,因为他们不能在同一边,所以第i对夫妻中a= 2*i表示妻子,b=2*i+1表丈夫. 有这样的关系:
a在左边,那么b就在右边,a*2->b*2+1
a在右边,那么b就在左边,a*2+1->b*2
b在左边,那么a就在右边,b*2->a*2+1
b在右边,那么a就在左边,b*2+1->a*2
然后对于每对有奸情的人a与b,因为它们不能同时在新娘对面(右边),所以:
a*2+1->b*2
b*2+1->a*2
注意首先我们定了新娘(0号)在左边,新郎(第1号人)一定在右边,所以我们要先加上:
0*2+1->0*2 和 1*2->1*2+1
这样就保证了新娘和新郎在固定的那边不动.
2-sat问题一定要动脑子。。。想办法转化成2-sat问题, 如果想出很暴力的也要想想,有没有更巧妙的转化?
先回顾下2-sat的实际应用: 在实际问题中,2-SAT问题在大多数时候表现成以下形式:有N对物品,每对物品中必须选取一个,也只能选取一个,并且它们之间存在某些限制关系(如某两个物品不能都选,某两个物品不能都不选,某两个物品必须且只能选一个,某个物品必选)等,这时,可以将每对物品当成一个布尔值(选取第一个物品相当于0,选取第二个相当于1),如果所有的限制关系最多只对两个物品进行限制,则它们都可以转化成9种基本限制关系,从而转化为2-SAT模型。
也就是限制关系不一定限制到每一个, 但是每组只能出一个是死的。那这题,夫妇之间就是个2-sat关系, 每一对夫妇只能选一个人做到新娘对面,也就是从2n个人选出n个人来, 其中通奸的不能同时出现, 这就变成了和平大使那题啦,如果u和v有通奸关系,就连边u->v',v->u'。有一点需要注意,就是要连一条边0->1,这样如果选了0就必须选1,那么就矛盾了,所以0一定不被选,选出来的就是新郎那一边的。很巧妙啊!这样连边也可以这样思考, 他说的是不能同时出现在对面, 也就是可以都不出现在他对面, 这样就是 选了i',j'了,这样两个i,j都去新娘那边了。。 如果通奸的人 必须一人一边的话, 那么就必须是 i-j', j-i',i'-j,j'-i了~ 注意不能同时出现跟一边一人的区别~
#include <iostream>#include <cstring>#include <cstdio>#include <vector>#include <stack>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 2e4 + 5;int n, m, low[maxn], dfn[maxn], id[maxn], scc_cnt, dfs_cnt, cnt[maxn];int S[maxn], T[maxn], D[maxn], in[maxn], col[maxn], opp[maxn];vector<int> v[maxn], vt[maxn];stack<int> s;void init(){ memset(low, 0, sizeof(low)); memset(id, 0, sizeof(id)); memset(dfn, 0, sizeof(dfn)); memset(in, 0, sizeof(in)); memset(col, -1, sizeof(col)); memset(opp, 0, sizeof(opp)); scc_cnt = dfs_cnt = 0; for(int i = 0; i < maxn; i++) v[i].clear(); while(!s.empty()) s.pop();}void addedge(int x, int y){ v[x].push_back(y);}void addedge2(int x, int y){ vt[x].push_back(y);}void tarjan(int x){ dfn[x] = low[x] = ++dfs_cnt; s.push(x); for(int i = 0; i < v[x].size(); i++) { int to = v[x][i]; if(!dfn[to]) { tarjan(to); low[x] = min(low[x], low[to]); } else if(!id[to]) low[x] = min(low[x], dfn[to]); } if(low[x] == dfn[x]) { scc_cnt++; while(1) { int u = s.top(); s.pop(); id[u] = scc_cnt; if(x == u) break; } }}void scc(){ for(int i = 0; i < 2*n ; i++) if(!dfn[i]) tarjan(i);}int Q[maxn];void top(){ memset(in, 0, sizeof(in)); memset(col, -1, sizeof(col)); for(int i = 0; i < 2*n; i++) vt[i].clear(); for(int i = 0; i < 2*n; i++) { for(int j = 0; j < v[i].size(); j++) { int to = v[i][j]; if(id[i] == id[to]) continue; // 在同一个连通分量不用考虑 addedge2(id[to], id[i]); //反着存边 in[id[i]]++; //入度++ } } int frnt, rear; frnt = rear = 0; for(int i = 1; i <= scc_cnt; i++) if(!in[i]) Q[rear++] = i; while(frnt != rear) { int u = Q[frnt++]; if(col[u] == -1) //未染色 { col[u] = 1; //染色1 col[opp[u]] = 0; //对立点染色0 } for(int i = 0; i < vt[u].size(); i++) { int to = vt[u][i]; if(--in[to] == 0) Q[rear++] = to; } }}int main(){ while(~scanf("%d%d", &n, &m), n+m) { init(); int x, y; char ch1, ch2; while(m--) { scanf("%d%c%d%c", &x, &ch1, &y, &ch2); int i, j, ii, jj; if(ch1 == 'h') { i = x*2+1; ii = i-1; } else { i = x*2; ii = i+1; } if(ch2 == 'h') { j = y*2+1; jj = j-1; } else { j = y*2; jj = j+1; } addedge(i, jj); //i-j' addedge(j, ii); // j - i' } addedge(0, 1); scc(); int flag = 0; for(int i = 0; i < 2*n; i+=2) { if(id[i] == id[i+1]) { flag = 1; break; } opp[id[i]] = id[i+1]; opp[id[i+1]] = id[i]; } if(flag) { printf("bad luck\n"); continue; } top(); int goal = col[id[0]]; for(int i = 2; i < 2*n; i++) { if(col[id[i]] == goal) printf("%d%c ", i/2, i&1 ? 'h' : 'w'); } puts(""); } return 0;}
- 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 2sat
- poj 3648 Wedding 2-SAT
- 2-sat->poj 3648 Wedding
- POJ 3648 Wedding(2-SAT)
- 【POJ】3648 Wedding 2-sat
- poj 3648 Wedding 2-sat
- POJ 3648 Wedding 2-SAT
- POJ 3648Wedding 2-sat
- |poj 3648|2-SAT|Wedding
- POJ 3648 Wedding(2-SAT + 输出方案)
- POJ 3648 Wedding(2-sat方案输出,4级)
- 2-SAT ( Tarjan )——Wedding (POJ 3648)
- PPP中不同的状态参数传递方法
- JAVA面试题的详细答案
- 视图模板
- Dynamic CRM 2016使用WEB API创建查询记录(js)
- Spring AOP (二)
- POJ 3648-Wedding(2-SAT)
- Java并发编程---CountDownLatch
- Android Transition动画学习笔记 2
- 3秒后自动更新头条
- C数据结构-顺序栈
- jquery.min.js:2 Uncaught TypeError: $(...).DataTable is not a function
- 网狐荣耀最新版视频教程
- 输出杨辉三角形
- spring boot 2.0把spring boot data gemfire移除了