URAL 1382 Game with Cards (2-SAT)
来源:互联网 发布:cmd建立网络路径 编辑:程序博客网 时间:2024/05/19 08:36
题目大意:
给出n行描述,每行的两句话都是一句话是对的,一句话是错的,要求输出最终的牌号和人的编号匹配的情况下,每个人说的话中是第一句对还是第二句对,题目保证一定有解
大致思路:
对于每个人说的话可以视作一个命题,我们将这些命题编号从1到n; 对于命题 xi, 有两种状态,一种是前一句话对,一种是后一句话对,在2-SAT算法中将这两种状态分别用结点编号为 2*i 和 2*i + 1 的点来表示
那么对于每个命题xi,由于2-SAT算法本身保证了两个结点不会同时被染色,也就不会出现矛盾的情况,那么对于两个不同的命题 xi 和 xj 就需要看是否存在矛盾来进行连边。
对于命题 xi 和 xj :
2*i 2*i + 1
xi i -> a[i] b[i] -> c[i]
xj j -> a[j] b[j] -> c[j]
2*j 2*j + 1
由于i != j 当 a[i] == a[j] 时,由于两者同时出现将会产生矛盾, 需要连边 2*i -> 2*j + 1 和 2*j -> 2*i + 1 即如果 xi 为假(结点2*i被染色),那么 xj 为真即需要染色 2*i + 1,另外一个同理。
当 i == b[i] || a[i] == c[j] 时, 连边 2*i -> 2*j 和 2*j + 1 -> 2*i + 1
当b[i] == j || c[i] == a[j] 时, 连边 2*i + 1 -> 2*j + 1 和 2*j -> 2*i
当 b[i] == b[j] || c[i] == c[j] 时, 连边 2*i + 1 -> 2*j 和 2*j + 1 -> 2*i
然后用2-SAT算法跑一遍就可以了
这样子对于命题 xi 如果结点 2*i 被标记就说明第一句话为真,否则说明第二句话为真
代码如下:
Result : Accepted Memory : 7941 KB Time : 46 ms
/* * Author: Gatevin * Created Time: 2014/7/23 19:28:14 * File Name: test.cpp */#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;const double eps(1e-8);typedef long long lint;#define maxn 1010int n;int a[maxn], b[maxn], c[maxn];struct TwoSAT{ int n; vector <int> G[maxn*2]; bool mark[maxn*2]; int S[maxn*2], c; bool dfs(int x) { if(mark[x^1]) return false;//结点x的对立点已经标为成立 if(mark[x]) return true;//x已经被访问过,说明继续下去已经可以保证是对的了,不需要重复标记 mark[x] = true; S[c++] = x; for(unsigned int i = 0; i < G[x].size(); i++) if(!dfs(G[x][i])) return false;//递推x结点能得到的结果,进行标记 return true; } void init(int n) { this->n = n; for(int i = 0; i < n*2; i++) { G[i].clear(); } memset(mark, 0, sizeof(mark)); } //x = xval or y = yval void add_clause(int x, int xval, int y, int yval) { x = x*2 + xval; y = y*2 + yval; G[x^1].push_back(y); G[y^1].push_back(x); } bool solve() { for(int i = 0; i < n*2; i += 2) { if(!mark[i] && !mark[i + 1]) { c = 0; if(!dfs(i)) { while(c > 0) mark[S[--c]] = false;//dfs(i)如果失败就擦掉之前实验标记的点 if(!dfs(i + 1)) return false;//换dfs(i = 1)上如果依旧失败说明无解 } } } return true; }};TwoSAT answer;int main(){ scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d %d %d", &a[i], &b[i], &c[i]); } answer.init(n); for(int i = 1; i <= n; i++) { for(int j = i + 1; j <= n; j++) { if(a[i] == a[j]) answer.add_clause(i - 1, 1, j - 1, 1);//对应的连边方式,这里编号需要减一,方便异或运算 if(i == b[j] || a[i] == c[j]) answer.add_clause(i - 1, 1, j - 1, 0); if(j == b[i] || a[j] == c[i]) answer.add_clause(i - 1, 0, j - 1, 1); if(b[i] == b[j] || c[i] == c[j]) answer.add_clause(i - 1, 0, j - 1, 0); } } bool flag = answer.solve(); if(flag) { for(int i = 0; i < n*2; i += 2) { if(answer.mark[i]) printf("1"); else printf("2"); if(i != 2*n - 2) printf(" "); } } return 0;}
- URAL 1382 Game with Cards (2-SAT)
- URAL 1382 Game with Cards
- URAL 1382 Game with Cards 解题报告
- 3622 Bomb Game //2--SAT
- [HDU3622][2-sat]Bomb Game
- Game of Cards Gym
- HDU 3622 Bomb Game【2-SAT 问题】
- hdu 3622 Bomb Game#2-sat+二分
- HDU 3622 Bomb Game(2-SAT)
- hdu3622 Bomb Game(二分+2-SAT)
- HDU 3622 Bomb Game【2-SAT 问题】
- HDU 3622 Bomb Game 2-sat
- 2-sat->HDU 3622 Bomb Game
- hdu 3622 Bomb Game (二分+2-sat)
- HDU 3622 Bomb Game / 2-SAT
- HDU 3622 Bomb Game(2-SAT+二分)
- 【HDU】3622 Bomb Game 2-sat
- hdu 3622 Bomb Game (2-SAT)
- MapGIS完美转ArcGIS ShapeFile攻略
- ruby四种闭包
- js实现幻灯片轮播原理
- Android中文API —— VideoView
- 慧眼答题C++接口
- URAL 1382 Game with Cards (2-SAT)
- MyBatis 1章 入门(使用MyBatis完成CRUD)
- Cocos2d-x中触摸事件
- 静态数组和动态数组 内存分布
- 华安泰VIKOR“跨越者”解码服务器:深入系统全面应用
- poj 1151 线段树扫描线求图形面积
- ubuntu 12 + mod_wsgi 配置django项目
- MyBatis 2章 MyBatis与Spring整合
- 【Java就业培训教程】——多态成员特点