ACM POJ 2723 Get Luffy Out(2-SAT入门)
题目链接:http://poj.org/problem?id=2723
【题目大意】
有2n把钥匙,分成2组,给你每组的钥匙信息,并且每组的钥匙只能用一个。
有m个门,每个门有2个锁,只要打开一个锁这个门就开了。(顺序遇见m个门)
问你最多能够打开多少个门。
【解题思路】
因为只能门只能按照顺序打开,所以很自然二分是个很好的选择。
建图的依据:
1、每对钥匙a,b有(a->!b),(b->!a) 也就是 a and b = 0 a被用b不被用,或b被用a不被用,或a,b都不被用
2、每善门对应锁的钥匙a,b有(!a->b),(!b->a) 也就是 a or b = 1,用a能打开用b不能打开,或用b能打开用a不能打开,或用a能打开用b也能打开
用二分法求解:
我下面用了两种方法求解的,时间都差不多。也就是求解强连通分量的两种方法。
/*POJ 2723 Get Luffy OutAC代码 */ #include<stdio.h>#include<math.h>#include<iostream>using namespace std;const int MAXN=1<<12;const int MAXM=1<<24;struct Node{int l,r;}e[MAXN];struct Node1{int from,to,next;}edge1[MAXM],edge2[MAXM];int visit1[MAXN],visit2[MAXN],head1[MAXN],head2[MAXN],Belong[MAXN],T[MAXN];int tol1,tol2,Bcnt,Tcnt;int hash[MAXN];void add(int a,int b){ edge1[tol1].from=a;edge1[tol1].to=b;edge1[tol1].next=head1[a];head1[a]=tol1++; edge2[tol2].from=b;edge2[tol2].to=a;edge2[tol2].next=head2[b];head2[b]=tol2++;} void dfs1(int x){int j; visit1[x]=1;for(j=head1[x];j!=-1;j=edge1[j].next)if(visit1[edge1[j].to]==0) dfs1(edge1[j].to); T[Tcnt++]=x;} void dfs2(int x){int j; visit2[x]=1; Belong[x]=Bcnt;for(j=head2[x];j!=-1;j=edge2[j].next)if(visit2[edge2[j].to]==0) dfs2(edge2[j].to);} int main(){int i,j,n,m;int right,left,mid,ans;while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break;int a,b;for(i=0;i<n;i++) { scanf("%d%d",&a,&b); hash[a]=b; hash[b]=a; } for(i=0;i<m;i++) scanf("%d%d",&e[i].l,&e[i].r); left=0; right=m;while(left<=right) { mid=(left+right)/2;for(i=0;i<4*n;i++) { head1[i]=-1; head2[i]=-1; visit1[i]=0; visit2[i]=0; } tol1=tol2=0; Tcnt=Bcnt=0;for(i=0;i<2*n;i++) { add(i,hash[i]+2*n); } for(i=0;i<mid;i++) { if(e[i].l!=e[i].r) { add(e[i].l+2*n,e[i].r); add(e[i].r+2*n,e[i].l); } if(e[i].l==e[i].r) { add(e[i].l+2*n,e[i].l); } }for(i=0;i<4*n;i++)if(!visit1[i]) dfs1(i); for(i=Tcnt-1;i>=0;i--) {if(!visit2[T[i]]) { dfs2(T[i]); Bcnt++; } } for(i=0;i<2*n;i++) {if(Belong[i]==Belong[i+2*n]) break; } if(i>=2*n) { ans=mid;left=mid+1; } else right=mid-1; } printf("%d\n",ans); } return 0;}
/*POJ 2723 Get Luffy OutAC代码 */#include<stdio.h>#include<math.h>#include<iostream>using namespace std;const int MAXN=1<<12;const int MAXM=1<<24;int n,m;struct Node{int l,r;}e[MAXN];struct Node1{int from,to,next;}edge[MAXM];int ecnt;int head[MAXN],Belong[MAXN],Stack[MAXN];int top,idx,b_cnt;int hash[MAXN];int DFN[MAXN],LOW[MAXN];bool Instack[MAXN];void add(int a,int b){ edge[ecnt].from=a;edge[ecnt].to=b;edge[ecnt].next=head[a];head[a]=ecnt++; } void Tarjan(int u){int i,v; DFN[u]=LOW[u]=(++idx); Stack[++top]=u; Instack[u]=true;for(i=head[u];i!=-1;i=edge[i].next) { v=edge[i].to;if(!DFN[v]) { Tarjan(v);if(LOW[u]>LOW[v])LOW[u]=LOW[v]; } else if(Instack[v]&&LOW[u]>DFN[v]) LOW[u]=DFN[v]; }if(LOW[u]==DFN[u]) { b_cnt++;do { v=Stack[top--]; Instack[v]=false; Belong[v]=b_cnt; }while(u!=v); } } int solve(){int i; b_cnt=idx=top=0;for(i=0;i<4*n;i++) { DFN[i]=LOW[i]=0; Belong[i]=0; Instack[i]=false; } for(i=0;i<4*n;i++)if(!DFN[i]) Tarjan(i);for(i=0;i<2*n;i++) {if(Belong[i]==Belong[i+2*n])return 0; } return 1;} int main(){int i,j;int right,left,mid,ans;while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break;int a,b;for(i=0;i<n;i++) { scanf("%d%d",&a,&b); hash[a]=b; hash[b]=a; } for(i=0;i<m;i++) scanf("%d%d",&e[i].l,&e[i].r); left=0; right=m;while(left<=right) { mid=(left+right)/2;for(i=0;i<4*n;i++) { head[i]=-1; } ecnt=0;for(i=0;i<2*n;i++) { add(i,hash[i]+2*n); } for(i=0;i<mid;i++) { if(e[i].l!=e[i].r) { add(e[i].l+2*n,e[i].r); add(e[i].r+2*n,e[i].l); } if(e[i].l==e[i].r) { add(e[i].l+2*n,e[i].l); } } if(solve()) { ans=mid;left=mid+1; } else right=mid-1; } printf("%d\n",ans); } return 0;}
ACM POJ 2723 Get Luffy Out(2-SAT入门)相关推荐
- HDU 1816, POJ 2723 Get Luffy Out(2-sat)
HDU 1816, POJ 2723 Get Luffy Out 题目链接 题意:N串钥匙.每串2把,仅仅能选一把.然后有n个大门,每一个门有两个锁,开了一个就能通过,问选一些钥匙,最多能通过多少个门 ...
- POJ 2723 Get Luffy Out【二分+2-sat】
题意:已知有 2*n把钥匙,这些钥匙两两一组,每组只能用其中的一把钥匙,有 m 个门,每个门上有两把锁,只要有一把锁被打开门就可以被打开, 一个门上可能是两把相同的锁,不同的门上也有可能有相同的锁,给 ...
- ACM POJ 题目分类(完整整理版本)
DP: 1011 NTA 简单题 1013 Great Equipment 简单题 1024 Calendar Game 简单题 ...
- ACM POJ 2965 The Pilots Brothers' refrigerator
http://poj.org/problem?id=2965 The Pilots Brothers' refrigerator Time Limit: 1000MS Memory Limit: 65 ...
- [ACM] POJ 1664 放苹果(n个相同小球放入m个相同盒子)
放苹果 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 25952 Accepted: 16509 Description ...
- 可行性nullpoj 2723 Get Luffy Out 2sat
最近研究可行性null,稍微总结一下,以后继续补充: 二分+2sat判可行性 每日一道理 最为值得珍惜的是今天,因为最容易流逝的就是今天,把握今天就是把握希望,分分秒秒只是瞬间,而所乘载的分分秒秒就叫 ...
- hdu1816 + POJ 2723开锁(二分+2sat)
题意: 有m层门,我们在最外层,我们要一层一层的进,每一层上有两把锁,我们只要开启其中的一把们就会开,我们有n组钥匙,每组两把,我们只能用其中的一把,用完后第二把瞬间就会消失,问你最多能开到 ...
- ACM POJ 2192 Zipper
题目大意:输入字符串a,b,c 要求推断c是否有a,b中的个字符保持原有顺序组合而成. 算法思想: DP 用dp[i][j]表示a的前0~i-1共i个字符和b的前0~j-1共j个字符是否构成c[i+j ...
- poj 2723 2-SAT问题
思路:二分枚举能开的门的数量,将每次枚举转换成2-SAT问题.这里存在的矛盾是假设有门上a,b两个锁,a锁对应于1号钥匙,而一号钥匙的配对是2号钥匙,b锁对应于3号钥匙,3号的配对是4号钥匙.那么2号 ...
最新文章
- FactoryMethod工厂方法模式升级成AbstractFactory抽象工厂模式
- 作者:秦兵(1968-),女,哈尔滨工业大学计算机科学与技术学院教授、博士生导师。...
- HID API for Linux, Mac OS X, and Windows
- wordpress文章发布时区时间延迟8小时解决方法
- 【语音隐写】基于matlab DWT音频数字水印嵌入提取【含Matlab源码 350期】
- 爆强的一句话,工作之余放松放松!
- 自动登录北科大USTB校园网
- oracle+sql+groupby,oracle学习笔记2:SQL执行
- python编程入门读书笔记1
- 以集成和管理为主要手段的企业报表中心架构设计
- 函数相乘和相除的导数及证明
- C++中的sort函数排序(快速排序)
- 如何查看本地服务器名称
- 按照拼音排序的SQL语句条件
- 2021-2027全球与中国成像色度计市场现状及未来发展趋势
- 常用IP地址端口对照表
- 【量化交易】量化分析概览
- 华硕主板如何用u盘启动计算机,华硕主板u盘启动是按f几_华硕主板BIOS设置U盘启动的方法-win7之家...
- 【网络攻击与防御】关于防御DDoS攻击的防火墙技术概述
- ALOS PALSAR卫星轨道参数读取
热门文章
- 【洛谷p1058】立体图(已完结)
- ruby简单的基础 4
- nodejs实现的简单接口
- 银行加速“去房地产化”
- 计算器是如何计算sin、cos等科学函数的值呢?
- C++--深入分析MFC文档视图结构(项目实践)
- CSS综合征病例,医药-churg-strauss 综合征 (css) 变应性嗜酸性肉芽肿.ppt
- java servlet 请求_java servlet请求数据
- 1.3 程序示例--梯度下降-机器学习笔记-斯坦福吴恩达教授
- MT6573驱动开发日志之touchpanel .