题意:
有2n把钥匙,每2个一组,给你每组的钥匙信息,并且每组的钥匙只能用一个。有m个门,每个门有2个锁,只要打开一个锁这个门就开了。问你最多能够打开多少个门。打开门必须是有序的,即你想要打开i就必须之前已经打开了i-1。
思路:
2-SAT求解能否打开前面k个门。
枚举或者二分答案k。注意从前往后枚举的时候,遇到不能打开则不用再往后枚举。详见代码。
二分写挫了?没有过,TLE。
枚举:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
二分(TLE):
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }