题意:
和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;
}