LOJ2723 Get Luffy Out
题目大意:给你n对钥匙,每对钥匙只可以用其中的任意一个,钥匙有编号,且不重复。有m个大门,每个门上有两个锁,每个锁对应一个编号的钥匙,只要打开两个锁中的一个就可以打开门。问用这n对钥匙最多可以打开多少大门(门有顺序)?
——————————————————————————————————————————————
每一个大门要打开,要么用A钥匙,要么用B钥匙,这是明现的2-SAT问题。
同一对钥匙,用了A钥匙就一定不能用B钥匙。
对于最多可以打开多少门,因为门有顺序,所以要二分答案。
——————————————————————————————————————————————
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int maxn=1050; 7 const int maxm=2100; 8 int n,m; 9 int keys[maxn<<1],doors[maxm][2]; 10 struct edge 11 { 12 int u,v,nxt; 13 }e[maxm<<1]; 14 int head[maxn<<1],js; 15 void addage(int u,int v) 16 { 17 e[++js].u=u;e[js].v=v; 18 e[js].nxt=head[u];head[u]=js; 19 } 20 int low[maxm<<1],dfn[maxm<<1],cnt,st[maxm<<1],top,lt[maxm<<1],lts; 21 void tarjan(int u) 22 { 23 low[u]=dfn[u]=++cnt; 24 st[++top]=u; 25 for(int i=head[u];i;i=e[i].nxt) 26 { 27 int v=e[i].v; 28 if(!dfn[v]) 29 { 30 tarjan(v); 31 low[u]=min(low[u],low[v]); 32 } 33 else if(!lt[v]) low[u]=min(low[u],dfn[v]); 34 } 35 if(low[u]==dfn[u]) 36 { 37 lt[u]=++lts; 38 while(st[top]!=u)lt[st[top--]]=lts; 39 --top; 40 } 41 } 42 bool pd(int x) 43 { 44 memset(head,0,sizeof head); 45 js=0; 46 for(int a,b,i=0;i<x;++i) 47 { 48 a=doors[i][0],b=doors[i][1]; 49 if(a==b)addage(keys[a]^1,keys[a]); 50 else 51 { 52 addage(keys[a]^1,keys[b]); 53 addage(keys[b]^1,keys[a]); 54 } 55 } 56 memset(low,0,sizeof low); 57 memset(dfn,0,sizeof dfn); 58 cnt=0; 59 memset(lt,0,sizeof lt); 60 lts=0; 61 top=0; 62 for(int i=2;i<n*2+2;++i) 63 if(!dfn[i])tarjan(i); 64 for(int i=1;i<n+1;++i) 65 if(lt[i<<1]==lt[(i<<1)^1])return 0; 66 return 1; 67 } 68 int main() 69 { 70 while(scanf("%d%d",&n,&m),n+m) 71 { 72 for(int a,b,i=1;i<=n;++i) 73 { 74 scanf("%d%d",&a,&b); 75 keys[a]=i<<1; 76 keys[b]=(i<<1)^1; 77 } 78 for(int i=0;i<m;++i) 79 scanf("%d%d",&doors[i][0],&doors[i][1]); 80 int l=0,r=m,ans=0; 81 while(l<=r) 82 { 83 int mid=(l+r)>>1; 84 if(pd(mid))ans=mid,l=mid+1; 85 else r=mid-1; 86 } 87 printf("%d\n",ans); 88 } 89 return 0; 90 }