题意:
和POJ2723差不多....唯一的区别在于前一题是把2N个要使分成了N对..而本题是组成了N对..说明可能有些钥匙出现在多个pair中...
题解:
上一题是以每一pair取哪一个来构图的...而本题就以每个钥匙拿还是不拿来构图....pair是有N个..而钥匙是有2N个..范围要留意...
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]; int Lnum,_next[MAXN],key[MAXN][2],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; Lnum=0,memset(_next,0,sizeof(_next)); for (i=1;i<=M;i++) { int x=door[i][0],y=door[i][1]; addline(x<<1,y<<1|1),addline(y<<1,x<<1|1); //对于一个门..必定是其中一把打开 } for (i=0;i<N;i++) { int x=key[i][0],y=key[i][1]; addline(x<<1|1,y<<1),addline(y<<1|1,x<<1); //每对至多取一个钥匙 } memset(dfn,0,sizeof(dfn)); memset(instack,false,sizeof(instack)); while (!mystack.empty()) mystack.pop(); DfsIndex=tpnum=0; for (i=0;i<(N<<2);i++) if (!dfn[i]) tarjan(i); for (i=0;i<(N<<1);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]); 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; }