CodeForces-776D The Door Problem
来源:互联网 发布:沈航网络自助平台套餐 编辑:程序博客网 时间:2024/06/01 09:37
The Door Problem
做这个题做了几天,中间各种事耽搁,不过也总结了很多。
题意:n扇门,初始状态可能开着也可能关着,m个开关,每个开关可以改变若干个门的状态,每扇门只由两个开关控制,问是否存在一种方法把所有的门都打开。
因为做并查集碰到了个问题,于是队友甩给我这道题,说实话很难想到用并查集,看了一下别人思路才知道的。
把门作为边,连接两个开关,如果门是开着,所连的两个开关属于一个集合,同时开关,如果门是关着,两个开关只能选一个,所以属于不同的集合,问题就转化到了求这些开关是否能分成两个集合。
这就是并查集问题了,用类似POJ-1703的方法是MLE,很不明白为什么,因为之前做的是HDU-5971,用的种类并查集却RE了,我还怀疑是递归的问题,可那道题数据量很小,不应该有这样的问题的。做这个题用种类并查集MLE,也是莫名奇妙。
MLE代码:
void init(){ for(int i=1; i<=n; i++) f[i]=p[i]=i; memset(mp,0,sizeof(mp)); tot=0;}int find(int x){ return f[x]==x?x:f[x]=find(f[x]);}int main(){ while(~scanf("%d%d",&n,&m)) { init(); for(int i=1; i<=n; i++) scanf("%d",&a[i]); for(int i=1; i<=m; i++) { int k,x; scanf("%d",&k); for(int j=1; j<=k; j++) { scanf("%d",&x); if(!mp[x][0]) mp[x][0]=i; else mp[x][1]=i; } } int flag=0; for(int i=1; i<=n; i++) { int u=mp[i][0],v=mp[i][1]; int f1=find(u),f2=find(v); if(a[i]) f[f1]=f2; else { if(p[v]==v) p[v]=u; if(p[u]==u) p[u]=v; int f3=find(p[u]),f4=find(p[v]); if(f1!=f4) f[f1]=f4; if(f2!=f3) f[f2]=f3; } } for(int i=1; i<=n&&!flag; i++) if(i!=p[i]&&find(i)==find(p[i])) flag=1; if(flag) puts("NO"); else puts("YES"); } return 0;}
AC代码:
void init(){ for(int i=1; i<N; i++) f[i]=p[i]=i; memset(mp,0,sizeof(mp));}int find(int x){ return f[x]==x?x:f[x]=find(f[x]);}void merge(int u,int v){ int f1=find(u),f2=find(v); f[f1]=f2;}int main(){ while(~scanf("%d%d",&n,&m)) { init(); for(int i=1; i<=n; i++) scanf("%d",&a[i]); for(int i=1; i<=m; i++) { int k,x; scanf("%d",&k); for(int j=1; j<=k; j++) { scanf("%d",&x); if(!mp[x][0]) mp[x][0]=i; else mp[x][1]=i; } } int flag=0; for(int i=1; i<=n; i++) { int u=mp[i][0],v=mp[i][1]; int f1=find(u),f2=find(v); int f3=find(u+m),f4=find(v+m); if(a[i]) {// f[f1]=f2; merge(u,v); merge(u+m,v+m); } else {// f[f1]=f4;// f[f2]=f3; merge(u,v+m); merge(v,u+m); } } for(int i=1; i<=m&&!flag; i++) if(find(i)==find(i+m)) flag=1; if(flag) puts("NO"); else puts("YES"); } return 0;}
很不明白为什么放在merge函数里分别合并就对了,但直接合并就MEL。队友说直接合并相当于把树压缩了,然后下次查找的时候不断的压栈,导致内存超限,还是不太明白。
不过同一个集合合并的时候也要将其对立合并,这里也不是很明白。
关键就在这个对立问题上,在做POJ-1703的时候,直接用第一份代码的方式就可以AC了,直接将其对立存起来,合并只需将自己与对立的对立合并就行了,但这里涉及到同集合合并问题,用相同的放法就行不通了。如果所有的关系都是对立的也许可以。第二种写法在很多种类并查集的题都可以过,所以总结是POJ/HDU的数据出水,误人啊。。
- 【codeforces 776D】The Door Problem
- CodeForces-776D The Door Problem
- Codeforces 776D The Door Problem 二分图判定
- codeforces-776D-The Door Problem(染色+建边+dfs)
- 【Codeforces 776 D The Door Problem】+ 并查集
- CodeForces 776D The Door Problem【并查集】
- Codeforces 776D The Door Problem 【并查集】
- codeforces Round 400 D-The Door Problem
- The Door Problem CodeForces
- Codeforces Round #400 D. The Door Problem (建图+搜索)
- codeforces round 400 D The Door Problem 2-SAT
- Codeforces-766D-The Door Problem(2-SAT-并查集解)
- codeforces 776D The Door Problem(带权并查集)
- Codeforces Round #400 (Div. 1 + Div. 2, combined) 776D. The Door Problem(待翻译)
- codeforce 776 D The Door Problem(DFS遍历)
- CF 776D The Door Problem TwoSAT 模板题
- Codeforces Round #400 (Div. 1 + Div. 2, combined) D. The Door Problem 开关--并查集
- Codeforces Round #400 (Div. 1 + Div. 2, combined)D. The Door Problem【2-sat Tarjan+思维建图】
- Rsrudio使用出现问题
- spark work task 源码分析
- 时间段的拼接
- JVM(PART III)对象的内存布局
- Linux文件的查看与权限
- CodeForces-776D The Door Problem
- Laravel5.4快速开发简书网站
- 牛客网--链表反转打印
- 常见智力题总结
- 2.5类型别名,auto, decltype
- Coursera 《Machine Learning》 编程作业7:K-means聚类和主成分分析
- TCP三次握手四次挥手的原因
- React的事件处理函数
- 2017年腾讯实习生在线笔试编程题(1)