Description
Behind the large door, there is a nesting prison, which consists of M floors. Each floor except the deepest one has a door leading to the next floor, and there are two locks in each of these doors. Ratish can pass through a door if he opens either of the two locks in it. There are 2N different types of locks in all. The same type of locks may appear in different doors, and a door may have two locks of the same type. There is only one key that can unlock one type of lock, so there are 2N keys for all the 2N types of locks. These 2N keys were divided into N pairs, and once one key in a pair is used, the other key will disappear and never show up again.
Later, Ratish found N pairs of keys under the rock and a piece of paper recording exactly what kinds of locks are in the M doors. But Ratish doesn't know which floor Luffy is held, so he has to open as many doors as possible. Can you help him to choose N keys to open the maximum number of doors?
Input
Output
Sample Input
3 6 0 3 1 2 4 5 0 1 0 2 4 1 4 2 3 5 2 2 0 0
Sample Output
4
//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=6000;
int V,E;//点数(1) 边数
struct edge//邻接表
{
int t;
int next;
};
int p[maxn];//表头节点
edge G[maxn*100];
int l;
void init()
{
memset(p,-1,sizeof(p));
l=0;
}
//添加边
void addedge(int u,int t)
{
G[l].t=t;
G[l].next=p[u];
p[u]=l++;
}
//tarjan算法 求有向图强联通分量
int dfn[maxn],lowc[maxn];
//dfn[u]节点u搜索的次序编号,lowc[u]u或者u的子树能够追溯到的栈中的最早的节点
int belg[maxn];//第i个节点属于belg[i]个强连通分量
int stck[maxn],stop;//stck栈
int instck[maxn];//第i个节点是否在栈中
int scnt;//强联通分量
int index;
void dfs(int i)
{
dfn[i]=lowc[i]=++index;
instck[i]=1;//节点i入栈
stck[++stop]=i;
for(int j=p[i];j!=-1;j=G[j].next)
{
int t=G[j].t;
//更新lowc数组
if(!dfn[t])//t没有遍历过
{
dfs(t);
if(lowc[i]>lowc[t]) lowc[i]=lowc[t];
}//t是i的祖先节点
else if(instck[t]&&lowc[i]>dfn[t]) lowc[i]=dfn[t];
}
//是强连通分量的根节点
if(dfn[i]==lowc[i])
{
scnt++;
int t;
do
{
t=stck[stop--];
instck[t]=0;
belg[t]=scnt;
}while(t!=i);
}
}
int tarjan()
{
stop=scnt=index=0;
memset(dfn,0,sizeof(dfn));
memset(instck,0,sizeof(instck));
for(int i=1;i<=V;i++)
{
if(!dfn[i]) dfs(i);
}
return scnt;
}
struct Point
{
int x,y;
};
Point a[maxn],b[maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2&&n)
{
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
a[i].x++,a[i].y++;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&b[i].x,&b[i].y);
b[i].x++,b[i].y++;
}
int l=0,r=m+1;//important r=m+1
n=n*2;
while(l<r)
{
int mid=(l+r)>>1;
V=2*n;init();
//选<=n 补选<=2*n
//x,y中最多选一个
for(int i=1;i<=n/2;i++)
{
addedge(a[i].x,a[i].y+n);
addedge(a[i].y,a[i].x+n);
}
//x,y中最少选一个
for(int i=1;i<=mid;i++)
{
addedge(b[i].x+n,b[i].y);
addedge(b[i].y+n,b[i].x);
}
tarjan();
int flag=1;
for(int i=1;i<=n;i++)
{
if(belg[i]==belg[i+n])
{
flag=0;break;
}
}
if(!flag) r=mid;
else l=mid+1;
}
printf("%d\n",l-1);
}
return 0;
}