hdu1814Peaceful Commission【2-SAT】输出最小解
2016-01-15 15:49
435 查看
居然1A了!!之前没调对居然只是多乘2了 (⊙﹏⊙)b 而且加边写反了==
题解:每个党派需要在两个代表中选一个,这2*n个代表中有彼此讨厌的m对人,输出n个去开会的代表
重点不在于怎么建边(建边这么so easy的事居然脑袋短路也是醉了==)在于怎么输出,网上的方法真的好麻烦,为什么非得染三个颜色的点啊我就不懂了,可能是模板的思路不好造成的吧
刘汝佳的书上说这个模板的思路是:逐一考虑没有赋值的变量(0~n-1范围内)即真、假未知的点,先假设这个变量是假(这个正好和题中要求一致,要是输出最大值就得先染色为真的结点了),然后顺着有向边标记所有能标记的点,如果发现对应为真的点被标记,那么“为假”的假定不成立,需要改成“为真”,然后重新标记。注意,这个算法没有回溯过程!。所以,当要重新标记时,之前那个点没有从0改成1.如果输出的“假”时候,需要保证“假”=1,“真”=0;其他情况
输出“真”
=============================分割线========================================
经测试,
答案也对,其实我还是觉得是数据不严谨导致的,虽然poj3648也是只判断==1不用对点==0,因为算法没有回溯过程,只是判断一个点并不能保证这个点是真正的“真”
算是为假期开个好头吧
题解:每个党派需要在两个代表中选一个,这2*n个代表中有彼此讨厌的m对人,输出n个去开会的代表
重点不在于怎么建边(建边这么so easy的事居然脑袋短路也是醉了==)在于怎么输出,网上的方法真的好麻烦,为什么非得染三个颜色的点啊我就不懂了,可能是模板的思路不好造成的吧
刘汝佳的书上说这个模板的思路是:逐一考虑没有赋值的变量(0~n-1范围内)即真、假未知的点,先假设这个变量是假(这个正好和题中要求一致,要是输出最大值就得先染色为真的结点了),然后顺着有向边标记所有能标记的点,如果发现对应为真的点被标记,那么“为假”的假定不成立,需要改成“为真”,然后重新标记。注意,这个算法没有回溯过程!。所以,当要重新标记时,之前那个点没有从0改成1.如果输出的“假”时候,需要保证“假”=1,“真”=0;其他情况
输出“真”
=============================分割线========================================
经测试,
for(int i=0;i<n;i++) { if(solver.mark[i<<1]) printf("%d\n",i<<1|1); else printf("%d\n",(i<<1)+2); }
答案也对,其实我还是觉得是数据不严谨导致的,虽然poj3648也是只判断==1不用对点==0,因为算法没有回溯过程,只是判断一个点并不能保证这个点是真正的“真”
/*********** hdu1814 2016.1.15 998MS 2924K 1784 B G++ ***********/ #include <iostream> #include<cstring> #include<cstdio> #include<vector> using namespace std; #define maxn 8004 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; if(mark[x]) return true; mark[x]=true; S[c++]=x; for(int i=0;i<G[x].size();i++) if(!dfs(G[x][i])) return false; 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)); } void add_clause(int x,int y) { G[x].push_back(y^1); G[y].push_back(x^1);///不一定是+1、-1!!而且本身就2n不用乘以2 } bool solve() { for(int i=0;i<2*n;i+=2) { if(!mark[i]&&!mark[i+1]) { c=0; if(!dfs(i)) { while(c>0) mark[S[--c]]=false; if(!dfs(i+1)) return false; } } } return true; } }solver; int n,m; int main() { // freopen("cin.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { solver.init(n); for(int i=0;i<m;i++) { int a,b; scanf("%d%d",&a,&b); a--;b--; solver.add_clause(a,b); } if(!solver.solve()) puts("NIE"); else { for(int i=0;i<n;i++) { if(solver.mark[i<<1]&!solver.mark[i<<1|1]) printf("%d\n",i<<1|1); else printf("%d\n",(i<<1)+2); } } } return 0; }
算是为假期开个好头吧
相关文章推荐
- 初探Backbone
- Android放大镜实现的两种方式
- zabbix 不能启动之非一般原因(配置的大意也可导致出错,也可以导致)
- 如何做优化,UITabelView才能更加顺滑
- js动画性能提升笔记
- 从MySQL获取数据
- MySQL事件的先后
- Android SlidingMenu 使用详解
- mysql查看执行计划
- (java)Evaluate Reverse Polish Notation
- mac上ide中无法获取环境变量的问题
- MTKandroid4.2.2编译环境OK
- Miku 修改背景音乐
- 使用fragment嵌套FragmentTabHost实现筛选切换框架
- BigTable论文阅读-个人翻译
- 网易 OpenStack 部署运维实战
- 控制点生成算法
- java 接口学习任务
- jsp加载访问时判断是由手机web端还是pc端
- (java)N-Queens