原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1816
题意:有m层楼,从一层到m层,要进入每层都要打开位于该层的两道门中的至少一道。门锁有2n种,每个门锁为2n种中的一种,可以重复。有2n把钥匙,分别对应2n种锁,但是钥匙两两一组,共n组,每组只能选一个来开门,被选中的可以多次使用,另一个一次都不能用。问最多能上多少层 。
分析:
首先对钥匙连线,两把钥匙a和b,如果选a那就不能选b,反过来一样。这个地方注意,我们是否需要连线如果不选a就选b这条线呢,是不需要的,因为这组钥匙可能根本用不到。
再对门连线,开门的钥匙a和b,如果没法用钥匙a,那就必须用钥匙b,反过来一样。同样需要注意,如果用了钥匙a,那么可不可以连线用b和不用b这条线呢,不需要的,因为对于一层来说只要开了一个门就可以。
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
#include<stack>
#include<algorithm>
#include<cmath>
#define INF 99999999
#define eps 0.0001
#define N ((1<<12)+10)
using namespace std;
int n, m;
int cnt, index;
int low[N];
int dfn[N];
int belong[N];
bool inStack[N];
vector<int> vec[N];
stack<int> s;
int key1[(1 << 10) + 10], key2[(1 << 10) + 10];
int door1[(1 << 11) + 10], door2[(1 << 11) + 10];
void init()
{
cnt = index = 0;
for (int i = 0; i < 4 * n; i++)
{
vec[i].clear();
inStack[i] = 0;
dfn[i] = 0;
}
}
void build(int level)
{
init();
for (int i = 0; i < n; i++)
{
vec[key1[i]].push_back(key2[i] + 2 * n);
vec[key2[i]].push_back(key1[i] + 2 * n);
}
for (int i = 0; i < level; i++)
{
vec[door1[i] + 2 * n].push_back(door2[i]);
vec[door2[i] + 2 * n].push_back(door1[i]);
}
}
void tarjan(int u)
{
low[u] = dfn[u] = ++index;
inStack[u] = 1;
s.push(u);
int v;
for (int i = 0; i < vec[u].size(); i++)
{
v = vec[u][i];
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (inStack[v])
low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u])
{
cnt++;
do
{
v = s.top();
s.pop();
belong[v] = cnt;
inStack[v] = 0;
} while (u != v);
}
}
bool solve()
{
for (int i = 0; i < 4 * n; i++)
if (!dfn[i])
tarjan(i);
for (int i = 0; i < 2 * n; i++)
if (belong[i] == belong[i + 2 * n])
return false;
return true;
}
int main()
{
while (~scanf("%d%d", &n, &m) && (n || m))
{
for (int i = 0; i < n; i++)
scanf("%d%d", &key1[i], &key2[i]);
for (int i = 0; i < m; i++)
scanf("%d%d", &door1[i], &door2[i]);
int l = 0;
int r = m;
int mid;
while (l <= r)
{
mid = (l + r) / 2;
build(mid);
if (solve())
l = mid + 1;
else
r = mid - 1;
}
printf("%d\n", l - 1);
}
return 0;
}