题意
题解
直接把POJ的那道题交上去就过了。
先说一下POJ那道题的做法。
二分能开的门个数,然后判断是是否合法。由于开门的是有先后顺序的,前边的没开,后边的门也开不了,所以在二分一个开门个数的时候,要限制图中某些边是否能选中。这个在对门建图的时候,对边加一个id,每次二分tarjan时,判断一下边的id是否小于当前二分的id,若小于等于的话,就表示这条边是在二分位置之间的限制关系,可以走,否则不可以走。
对于门和钥匙分别建图。
- 对于钥匙来说,选a不能选b,选b不能选a。
- 对于们来说,若a不选择必选b,若b不选择必选a。
他们之间逻辑是不同的。
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int head[nmax], tot;
struct edge {
int to, nxt, id;
}e[nmax<<1];
int low[10005], dfn[10005], color[10005], ss[10005], st, dfs_clock, scc;
bool instack[10005];
int n , m;
void add_edge(int u, int v, int id) {
e[tot].to = v;
e[tot].nxt = head[u];
e[tot].id = id;
head[u] = tot++;
}
void init() {
memset(head ,-1, sizeof head);
tot = 0;
}
void tarjan(int u, int x) {
low[u] = dfn[u] = ++dfs_clock;
ss[st++] = u ;
instack[u] = true;
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(e[i].id > x)
continue;
if(!dfn[v]) {
tarjan(v, x);
low[u] = min (low[u], low[v]);
} else if(instack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]) {
scc ++;
int tmp = 0;
while(1) {
tmp = ss[--st];
color[tmp] = scc;
instack[tmp] = false;
if(tmp == u)
break;
}
}
}
bool check(int x) {
memset(low, 0, sizeof low);
memset(dfn, 0, sizeof dfn);
memset(color, 0, sizeof color);
st = dfs_clock = scc = 0;
for(int i = 1; i <= 2 * n; ++i) {
if(!dfn[i])
tarjan(i, x);
}
for(int i = 1; i <= n; ++i) {
if(color[i] != 0 && color[i+n] != 0 && color[i] == color[i+n])
return false;
}
return true;
}
int main(){
while(scanf("%d %d", &n, &m) != EOF) {
if(n == 0 && m == 0)
break;
init();
int u , v;
for(int i = 1; i <= n; ++i) {
scanf("%d %d", &u, &v);
u ++;
v ++;
add_edge(u, v + n, -1);
add_edge(v, u + n, -1);
}
for(int i = 1; i <= m; ++i) {
scanf("%d %d", &u, &v);
u ++;
v ++;
add_edge(v + n, u, i);
add_edge(u + n, v, i);
}
if(n == 0) {
printf("0\n");
continue;
}
int ans = 0, l = 0 , r = m;
while(l <= r) {
int mid = (l + r) >>1;
if(check(mid)) {
ans = mid;
l = mid + 1;
}else r = mid - 1;
}
printf("%d\n",ans);
}
return 0;
}