题意:
主人公在一个类似于塔结构的地方..每一层有一个门..门上有两个钥匙孔..只要有其中的一片钥匙就能打开门继续往上走了(一个门可能有两个相同的钥匙孔..也可能好几个门都有相同的钥匙孔..)..而所有的钥匙被分成了N个pair..每个pair中只能拿一把钥匙..现在问主人公最多能进入第几层...
题解:
值得注意的是必须通过了K层才能进入K+1层...这样就形成了一种单调关系...可以用二分来解决了..二分层数..然后2-sat判断...
Program:
#include<iostream> #include<stdio.h> #include<string.h> #include<cmath> #include<queue> #include<stack> #include<set> #include<time.h> #include<map> #include<algorithm> #define ll long long #define eps 1e-5 #define oo 10007 #define pi acos(-1.0) #define MAXN 5005<<1 #define MAXM 5000005<<1 using namespace std; struct node { int y,next; }line[MAXM]; vector<int> T[MAXN]; int Lnum,_next[MAXN],key[MAXN][2],hash[MAXN],door[MAXN][2]; int dfn[MAXN],low[MAXN],tp[MAXN],tpnum,DfsIndex; bool instack[MAXN]; stack<int> mystack; void addline(int x,int y) { line[++Lnum].next=_next[x],_next[x]=Lnum,line[Lnum].y=y; } void tarjan(int x) { instack[x]=true,mystack.push(x); dfn[x]=low[x]=++DfsIndex; for (int k=_next[x];k;k=line[k].next) { int y=line[k].y; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); }else if (instack[y]) low[x]=min(low[x],dfn[y]); } if (low[x]==dfn[x]) { tpnum++; do { x=mystack.top(); mystack.pop(); instack[x]=false; tp[x]=tpnum; }while (low[x]!=dfn[x]); } } bool _2sat(int N,int M) { int i,m,k; for (i=0;i<(N<<1);i++) T[i].clear(); for (i=1;i<=M;i++) T[door[i][0]].push_back(door[i][1]), T[door[i][1]].push_back(door[i][0]); Lnum=0,memset(_next,0,sizeof(_next)); for (i=0;i<N;i++) { int x=key[i][0],y=key[i][1]; m=T[y].size(); for (k=0;k<m;k++) addline(i<<1,hash[T[y][k]]); m=T[x].size(); for (k=0;k<m;k++) addline(i<<1|1,hash[T[x][k]]); } memset(dfn,0,sizeof(dfn)); memset(instack,false,sizeof(instack)); while (!mystack.empty()) mystack.pop(); DfsIndex=tpnum=0; for (i=0;i<(N<<1);i++) if (!dfn[i]) tarjan(i); for (i=0;i<N;i++) if (tp[i<<1]==tp[i<<1|1]) return false; return true; } int main() { int N,M,i; while (~scanf("%d%d",&N,&M) && N) { for (i=0;i<N;i++) { scanf("%d%d",&key[i][0],&key[i][1]); hash[key[i][0]]=i<<1,hash[key[i][1]]=i<<1|1; } for (i=1;i<=M;i++) scanf("%d%d",&door[i][0],&door[i][1]); int l=0,r=M+1,mid; while (r-l>1) { mid=l+r>>1; if (!_2sat(N,mid)) r=mid; else l=mid; } printf("%d\n",l); } return 0; }