POJ 2723 Get Luffy Out (2-SAT)
2017-07-20 11:05
441 查看
题意:
给你n对钥匙,一共2*n个钥匙。然后不一定谁和谁配对,但给你这n个配对关系。
一对钥匙里,你只能选一把钥匙。
然后你面前有1扇门,门有两个锁,你只要任意打开一个锁就能进去,然后你面前又有一扇门。。。
给你n扇门各自所需要的锁。现在问你最多你可以过多少扇门。
注意配对关系i,j,只能选其中一个,所以这么建边:
ae(i,j+n) ae(j,i+n) ae(i+n,j) ae(j+n,i)
注意这里我是用i代表选,i+n代表不选。
但是这题要是这么建边无疑是麻烦了一点。。直接用一个数组key将钥匙的对应关系存下来,然后自然就不能同时选了,后边只需要讨论门就好了。
接下来是门:对于当前这个门,可以由i或j钥匙打开,
所以我们可以这么建边:
ae(key[i],j) ae(key[j],i);
代表着选i的对立点(不选i)就得选j,否则打不开门
代表着选j的对立点(不选j)就得选i,否则打不开门
然后跑tarjan判断能否可行。
我在做这题的时候看到别人有的是用二分求的最大门数,然而我觉得二分的话建边有些麻烦就没用(而且建边也会浪费不少操作。。),所以我就加两条边判断一次,不行的话就减减输出。(我一开始忘了在全开门之后减减了。。wa死我了。。2s时间只跑了450ms,所以根本没必要二分啊。。)
#include <iostream> #include <algorithm> #include <cstdio> #include <string.h> #include <queue> #include <cmath> #define pi acos(-1.0) #define eps 1e-6 typedef long long int lli; using namespace std; const int maxn = 4200; struct edge{ int from,to,v,next; }ed[400000],door[20000]; int head[maxn]; int cnte; void ae(int x,int y){ ed[++cnte].to = y; ed[cnte].next = head[x]; head[x]=cnte; } int dfn[maxn],low[maxn],vis[maxn],stak[maxn],belong[maxn],cntc,cnts,index;//strong connected component //cnt of stack void dfs(int u){ dfn[u]=low[u] = ++index; stak[cnts++]=u; vis[u]=1; for(int i = head[u];i!=-1;i=ed[i].next){ int v = ed[i].to; if(!dfn[v]){ dfs(v); low[u] = min(low[u],low[v]); } else if(vis[v]){ low[u] = min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ cntc++;int v; do{ v = stak[--cnts]; vis[v] = 0; belong[v] = cntc; }while(v!=u); } } int n,m; void tarjan(){ for(int i = 0;i < 2*n;i++){ if(!dfn[i]){ dfs(i); } } } int key[4220]; void ini(){ memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(belong,0,sizeof(belong)); cntc=index=0; } bool jud(){ for(int i = 0;i < 2*n;i++){ if(belong[i]!=0 &&belong[i] == belong[key[i]]){ return false; } } return true; } int main(){ int t; while(~scanf("%d%d",&n,&m),n||m){ memset(head,-1,sizeof(head));memset(key,0,sizeof(key)); cnte = 0; int a,b; for(int i = 1;i <= n;i++){ scanf("%d%d",&a,&b); key[a] = b;key[b] = a; } for(int i = 1;i <= m;i++){ scanf("%d%d",&door[i].from,&door[i].to); } int i; for(i = 1;i <= m;i++){ ae(key[door[i].from],door[i].to); ae(key[door[i].to],door[i].from); ini();tarjan(); if(!jud()){ i--; break; } } if(i == m+1) i--; printf("%d\n",i); } }
相关文章推荐
- poj 2723 Get Luffy Out(图论-2-sat)
- POJ 2723 Get Luffy Out(2-SAT)
- poj 2723 Get Luffy Out 【2-sat + 二分查找判断可行性】
- poj2723 Get Luffy Out (二分+2-SAT)
- POJ-2723-Get Luffy Out(2-sat)
- 2-sat->poj 2723 Get Luffy Out
- Get Luffy Out (poj 2723 二分+2-SAT)
- POJ 2723 Get Luffy Out 2-SAT&&二分搜索
- poj 2723 Get Luffy Out 二分答案+2-sat+如何建图
- poj 2723 Get Luffy Out 2-SAT
- HDU 1816, POJ 2723 Get Luffy Out(2-sat)
- POJ 2723 Get Luffy Out(2-SAT + 二分)
- POJ2723-Get Luffy Out(2-SAT)
- POJ 2723 Get Luffy Out(2-SAT)
- POJ 2723 Get Luffy Out(2-SAT)
- [2-sat+二分]poj 2723 Get Luffy Out
- Get Luffy Out poj 2723 Tarjan+2-SAT
- POJ2723-Get Luffy Out(2-SAT)
- poj 2723 Get Luffy Out(2-sat)
- HDU 1816, POJ 2723 Get Luffy Out(2-sat)