题目大意:
有2n把钥匙,分成2组,给你每组的钥匙信息,并且每组的钥匙只能用一个。
有m个门,每个门有2个锁,只要打开一个锁这个门就开了。(顺序遇见m个门)
问你最多能够打开多少个门。
思路分析:
2n个钥匙,定义4n个节点,1~2n中的i表示用第i个钥匙。 2n+1~4n中的j, 表示不用j - 2n号钥匙。
那么对与给你的n组钥匙的每一组a和b。
有边<a, b + 2n> 和 <b, a + 2n>(只能选一个钥匙)
对于给你的m个门的两个锁a和b
有边<a + 2n, b> <b + 2n, a> 至少选一个。
然后枚举1~m个门,看看最后能到第几个门能够满足条件(数据比较少,不用二分也能过)
CODE:
/*POJ2-SAT第二题*/
/*AC代码:1000ms(没用二分)*/
#include <iostream>
#define MAXN 6000
struct edge
{
int v,next;
edge(){}
edge(int v1,int next1)
{
v=v1;next=next1;
}
}E[2000000];
int head[MAXN],ecnt;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
bool Instack[MAXN];
int cnt,Index,top,N,M;
void Insert(int u,int v)
{
E[ecnt]=edge(v,head[u]);
head[u]=ecnt++;
}
void Tarjan(int u)
{
int v,i;
Low[u]=DFN[u]=++Index;
Instack[u]=true;
Stack[++top]=u;
for(i=head[u];i!=-1;i=E[i].next)
{
v=E[i].v;
if(!DFN[v])
{
Tarjan(v);
if(Low[u]>Low[v])
Low[u]=Low[v];
}
else if(Instack[v]&&Low[u]>DFN[v])
Low[u]=DFN[v];
}
if(Low[u]==DFN[u])
{
cnt++;
do{
v=Stack[top--];
Belong[v]=cnt;
Instack[v]=false;
}while(v!=u);
}
return;
}
int main()
{
int i,j,u,v;
while(scanf("%d%d",&N,&M)!=EOF)
{
if(N==0&&M==0) break;
ecnt=0;
memset(head,-1,sizeof(head));
for(i=0;i<N;i++)
{
scanf("%d%d",&u,&v);
Insert(u,v+2*N);//注意,表示只能取一个
Insert(v,u+2*N);
}
int ans=0;
bool flag=true;
for(i=0;i<M;i++)
{
scanf("%d%d",&u,&v);
if(flag)
{
Insert(u+2*N,v);Insert(v+2*N,u);//表示只能不取一个(至少去一个)
Index=cnt=top=0;
memset(Instack,false,sizeof(Instack));
memset(DFN,0,sizeof(DFN));
memset(Low,0,sizeof(Low));
for(j=0;j<2*N;j++)
if(!DFN[j])
Tarjan(j);
for(j=0;j<N;j++)
if(Belong[j]==Belong[j+2*N])
{flag=false;break;}
if(flag) ans++;
}
}
printf("%d\n",ans);
}
return 0;
}