题意是说,2N把钥匙,M个门,每个门有两个锁,开其中一个就可以,把2N把钥匙分成Npair,用了其中一把,另一把就不再出现,而用的那把可以循环使用,问最多能开多少扇门?
解法:2-SAT+二分
因为开门是有序的,所以二分答案。
设有4N把锁,其中1~2N表示锁i(1<=i<=2N)使用,2N+1~4N表示锁j(1<=j<=2N)抛弃,接着就是激动人心的建图!先建不能共存的锁,再对门进行建图。最后就缩点
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <limits.h>
using namespace std;
int lowbit(int t){return t&(-t);}
int countbit(int t){return (t==0)?0:(1+countbit(t&(t-1)));}
int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a>b?b:a;}
#define LL long long
#define PI acos(-1.0)
#define N 1200*4
#define INF INT_MAX
#define eps 1e-8
#define FRE freopen("a.txt","r",stdin)
int low[N],dfn[N];
int belong[N];
int key[1200][2],lock[3000][2];
bool inStack[N],vis[N];
vector<int> v[N];
stack<int> st;
int n,m;
int step;
int t;
void tarjan(int u)
{
int i;
step++;
st.push(u);
low[u]=dfn[u]=step;
vis[u]=1;
inStack[u]=1;
for(i=0;i<v[u].size();i++)
{
int x=v[u][i];
if(!vis[x])
{
tarjan(x);
low[u]=min(low[u],low[x]);
}
else
if(inStack[x])
low[u]=min(low[u],dfn[x]);
}
if(low[u]==dfn[u])
{
t++;
while(1)
{
int x=st.top();
st.pop();
belong[x]=t;
inStack[x]=0;
if(x==u)break;
}
}
}
void init()
{
int i;
for(i=0;i<=4*n;i++)v[i].clear();
while(!st.empty())st.pop();
}
bool judge()
{
int i,j;
t=0;step=0;
memset(vis,0,sizeof(vis));
memset(inStack,0,sizeof(inStack));
for(i=1;i<=4*n;i++)
if(!vis[i])tarjan(i);
for(i=1;i<=2*n;i++)
if(belong[i]==belong[i+2*n])
return false;
return true;
}
void build(int mid)
{
int i,j;
int a,b;
init();
for(i=1;i<=n;i++)
{
a=key[i][1],b=key[i][2];
v[a].push_back(b+2*n);
v[b].push_back(a+2*n);
}
for(i=1;i<=mid;i++)
{
a=lock[i][1],b=lock[i][2];
if(a==b)v[a+2*n].push_back(a);
else
{
v[a+2*n].push_back(b);
v[b+2*n].push_back(a);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)&&(n+m))
{
int i,j;
for(i=1;i<=n;i++)
{
scanf("%d%d",&key[i][1],&key[i][2]);
key[i][1]++;
key[i][2]++;
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&lock[i][1],&lock[i][2]);
lock[i][1]++;
lock[i][2]++;
}
int l=1,r=m,mid;
int ans;
while(l<=r)
{
mid=(l+r)>>1;
build(mid);
if(judge())
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}