poj2723Get Luffy Out (2-SAT)

题意:

有2n把钥匙,每2个一组,给你每组的钥匙信息,并且每组的钥匙只能用一个。有m个门,每个门有2个锁,只要打开一个锁这个门就开了。问你最多能够打开多少个门。打开门必须是有序的,即你想要打开i就必须之前已经打开了i-1。

 

思路:

2-SAT求解能否打开前面k个门。

枚举或者二分答案k。注意从前往后枚举的时候,遇到不能打开则不用再往后枚举。详见代码。

二分写挫了?没有过,TLE。

 

枚举:

  1 #include<stdio.h>
  2 #include<math.h>
  3 #include<string.h>
  4 #define N 5000
  5 
  6 struct edge{
  7     int v;
  8     int next;
  9 }e[N*10];
 10 int last[N];
 11 int tot;
 12 
 13 void add(int u,int v){
 14     e[tot].v = v;
 15     e[tot].next = last[u];
 16     last[u] = tot++;
 17     return ;
 18 }
 19 
 20 int n,m;
 21 
 22 int min(int a,int b){
 23     return a<b?a:b;
 24 }
 25 int scnt , idx, top;
 26 int stack[N];
 27 int dfn[N],low[N];
 28 bool vis[N];
 29 int id[N];
 30 
 31 void tarjan(int u){
 32     vis[u] = 1;
 33     dfn[u] = low[u] = idx++;
 34     stack[++top] = u;
 35     for (int j = last[u];j!=-1;j=e[j].next){
 36             int v = e[j].v;
 37             if (dfn[v] == -1){
 38                 tarjan(v);
 39                 low[u] = min(low[u],low[v]);
 40             }else if (vis[v] ==1 && dfn[v] < low[u]){
 41                 low[u] = dfn[v];
 42             }
 43         }
 44     if (low[u] == dfn[u]){
 45         while (stack[top] != u){
 46             int v = stack[top];
 47             top--;
 48             vis[v] = 0;
 49             id[v] = scnt;
 50         }
 51         top--;
 52         vis[u] = 0;
 53         id[u] = scnt;
 54         scnt++;
 55     }
 56 }
 57 
 58 bool solve(){
 59     scnt = idx = top = 0;
 60     memset(dfn,-1,sizeof(dfn));
 61     memset(vis,0,sizeof(vis));
 62     for (int i=0;i<4*n;i++)
 63         if (dfn[i] == -1)
 64             tarjan(i);
 65     for (int i=0;i<2*n;i++)
 66         if (id[i] == id[i+2*n])
 67             return false;
 68     return true;
 69 
 70 }
 71 
 72 int main()
 73 {
 74     while (scanf("%d%d",&n,&m)==2)
 75     {
 76         if (n==0 && m==0)
 77             break;
 78         memset(last,-1,sizeof(last));
 79         tot = 0;
 80         for (int i=1;i<=n;i++){
 81             int u, v;
 82             scanf("%d%d",&u,&v);
 83             add(u,v+2*n);
 84             add(v,u+2*n);
 85         }
 86         int ans = 0;
 87         int flag = 0;
 88         for (int i=1;i<=m;i++){
 89             int u,v;
 90             scanf("%d%d",&u,&v);
 91             if (flag)
 92                 continue;
 93             add(u+2*n,v);
 94             add(v+2*n,u);
 95             if (solve()){
 96                 ans = i;
 97             }else{
 98                 flag = 1;
 99             }
100         }
101         printf("%d\n",ans);
102     }
103     return 0;
104 }
POJ2723(枚举+2SAT)

二分(TLE):

  1 #include<stdio.h>
  2 #include<math.h>
  3 #include<string.h>
  4 #define N 5000
  5 
  6 struct edge{
  7     int v;
  8     int next;
  9 }e[N*10],ee[N*10];
 10 int last[N],lastt[N];
 11 int tot,tott;
 12 
 13 void add(int u,int v){
 14     e[tot].v = v;
 15     e[tot].next = last[u];
 16     last[u] = tot++;
 17     return ;
 18 }
 19 
 20 int n,m;
 21 
 22 int min(int a,int b){
 23     return a<b?a:b;
 24 }
 25 int scnt , idx, top;
 26 int stack[N];
 27 int dfn[N],low[N];
 28 bool vis[N];
 29 int id[N];
 30 bool vvv[N];
 31 
 32 void tarjan(int u){
 33     vvv[u] = 1;
 34     vis[u] = 1;
 35     dfn[u] = low[u] = idx++;
 36     stack[++top] = u;
 37     for (int j = last[u];j!=-1;j=e[j].next){
 38             int v = e[j].v;
 39             if (dfn[v] == -1){
 40                 tarjan(v);
 41                 low[u] = min(low[u],low[v]);
 42             }else if (vis[v] ==1 && dfn[v] < low[u]){
 43                 low[u] = dfn[v];
 44             }
 45         }
 46     if (low[u] == dfn[u]){
 47         while (stack[top] != u){
 48             int v = stack[top];
 49             top--;
 50             vis[v] = 0;
 51             id[v] = scnt;
 52         }
 53         top--;
 54         vis[u] = 0;
 55         id[u] = scnt;
 56         scnt++;
 57     }
 58 }
 59 
 60 bool solve(){
 61     scnt = idx = top = 0;
 62     memset(dfn,-1,sizeof(dfn));
 63     memset(vis,0,sizeof(vis));
 64     memset(vvv,0,sizeof(vvv));
 65     for (int i=0;i<4*n;i++)
 66         if (dfn[i] == -1)
 67             tarjan(i);
 68     for (int i=0;i<2*n;i++)
 69         if (id[i] == id[i+2*n])
 70             return false;
 71     return true;
 72 
 73 }
 74 
 75 int a[N];
 76 int b[N];
 77 
 78 
 79 int calc(){
 80     memcpy(ee,e,sizeof(e));
 81     for (int i=0;i<N;i++)
 82         lastt[i] = last[i];
 83     tott = tot;
 84 
 85     int l = 0, r = m;
 86     while (l < r){
 87         memcpy(e,ee,sizeof(ee));
 88         for (int i=0;i<N;i++)
 89             last[i] = lastt[i];
 90 
 91         tot = tott;
 92         int mid = (l + r)/2;
 93         for (int i=1;i<=mid;i++)
 94         {
 95             int u = a[i];
 96             int v = b[i];
 97             add(u+2*n,v);
 98             add(v+2*n,u);
 99         }
100         if (solve()){
101             l = mid;
102         }else{
103             r = mid - 1;
104         }
105     }
106     return l;
107 }
108 int main()
109 {
110     while (scanf("%d%d",&n,&m)==2)
111     {
112         if (n==0 && m==0)
113             break;
114         memset(last,-1,sizeof(last));
115         tot = 0;
116         for (int i=1;i<=n;i++){
117             int u, v;
118             scanf("%d%d",&u,&v);
119             add(u,v+2*n);
120             add(v,u+2*n);
121         }
122         for (int i=1;i<=m;i++){
123             scanf("%d%d",&a[i],&b[i]);
124         }
125 
126         printf("%d\n",calc());
127     }
128     return 0;
129 }
poj2723(二分+2SAT)

 

 

转载于:https://www.cnblogs.com/wangsouc/articles/3267226.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值