題意是說,2N把鑰匙,M個門,每個門有兩個鎖,開其中一個就可以,把2N把鑰匙分成Npair,用了其中一把,另一把就不再出現,而用的那把可以迴圈使用,問最多能開多少扇門?
解法:2-SAT+二分
因為開門是有序的,所以二分答案。
設有4N把鎖,其中1~2N表示鎖i(1<=i<=2N)使用,2N+1~4N表示鎖j(1<=j<=2N)拋棄,接著就是激動人心的建圖!先建不能共存的鎖,再對門進行建圖。最後就縮點
#include <vector>#include <list>#include <map>#include <set>#include <queue>#include <string.h>#include <deque>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <limits.h>using namespace std;int lowbit(int t){return t&(-t);}int countbit(int t){return (t==0)?0:(1+countbit(t&(t-1)));}int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}int max(int a,int b){return a>b?a:b;}int min(int a,int b){return a>b?b:a;}#define LL long long#define PI acos(-1.0)#define N 1200*4#define INF INT_MAX#define eps 1e-8#define FRE freopen("a.txt","r",stdin)int low[N],dfn[N];int belong[N];int key[1200][2],lock[3000][2];bool inStack[N],vis[N];vector<int> v[N];stack<int> st;int n,m;int step;int t;void tarjan(int u){ int i; step++; st.push(u); low[u]=dfn[u]=step; vis[u]=1; inStack[u]=1; for(i=0;i<v[u].size();i++) { int x=v[u][i]; if(!vis[x]) { tarjan(x); low[u]=min(low[u],low[x]); } else if(inStack[x]) low[u]=min(low[u],dfn[x]); } if(low[u]==dfn[u]) { t++; while(1) { int x=st.top(); st.pop(); belong[x]=t; inStack[x]=0; if(x==u)break; } }}void init(){ int i; for(i=0;i<=4*n;i++)v[i].clear(); while(!st.empty())st.pop();}bool judge(){ int i,j; t=0;step=0; memset(vis,0,sizeof(vis)); memset(inStack,0,sizeof(inStack)); for(i=1;i<=4*n;i++) if(!vis[i])tarjan(i); for(i=1;i<=2*n;i++) if(belong[i]==belong[i+2*n]) return false; return true;}void build(int mid){ int i,j; int a,b; init(); for(i=1;i<=n;i++) { a=key[i][1],b=key[i][2]; v[a].push_back(b+2*n); v[b].push_back(a+2*n); } for(i=1;i<=mid;i++) { a=lock[i][1],b=lock[i][2]; if(a==b)v[a+2*n].push_back(a); else { v[a+2*n].push_back(b); v[b+2*n].push_back(a); } }}int main(){ while(scanf("%d%d",&n,&m)&&(n+m)) { int i,j; for(i=1;i<=n;i++) { scanf("%d%d",&key[i][1],&key[i][2]); key[i][1]++; key[i][2]++; } for(i=1;i<=m;i++) { scanf("%d%d",&lock[i][1],&lock[i][2]); lock[i][1]++; lock[i][2]++; } int l=1,r=m,mid; int ans; while(l<=r) { mid=(l+r)>>1; build(mid); if(judge()) { ans=mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); } return 0;}