您的位置:首页 > 其它

poj 2723 Get Luffy Out 二分+2-SAT

2017-06-23 22:04 519 查看
题目大意:有n对钥匙,每一对拿了一个另外一个就会消失,有m扇门,每一扇门有两个锁,分别对应2*n把钥匙,求按顺序最多可开多少门。

比较明显的模型呢,先把对立边记录下,然后直接二分用2-sat判断,毕竟2-sat不能直接求出答案只能判断是否可行。

二分的时候连前mid扇门就好啦。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n, m;
const int N = 3e5 + 5;
unsigned int read()
{
unsigned int x = 0, f = 1; char ch = getchar();
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x*f;
}
int head
, nxt
, go
, val
;
int oppo
,low
,dfn
;
int a
, b
,block
,stk
,in
;
int tot,tim,bl,top;
inline void add(int x, int y)
{
go[++tot] = y;
nxt[tot] = head[x];
head[x] = tot;
}
inline void tarjan(int x)
{
dfn[x] = low[x] = ++tim;
stk[++top] = x;
in[x] = 1;
for (int i = head[x]; i; i = nxt[i])
{
int v = go[i];
if (!dfn[v])
{
tarjan(v);
low[x] = min(low[v], low[x]);
}
else if (in[v]==1) low[x] = min(dfn[v], low[x]);
}
if (low[x] == dfn[x])
{
bl++;
int  j=0;
do
{
j = stk[top--];
in[j] = 0;
block[j] = bl;
} while (x != j);
}
}
inline bool check(int m)
{
if (!m)return 1;
tim = tot = 0;
memset(nxt, 0, sizeof(nxt));
memset(head, 0, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(block, 0, sizeof(block));
fo(i, 1, m)
{
add(oppo[a[i]], b[i]);
add(oppo[b[i]], a[i]);
}
fo(i, 0, 2*n-1)if (!dfn[i])tarjan(i);
fo(i, 0, 2 * n-1)if (block[i] == block[oppo[i]])return 0;
return 1;
}
int main()
{
n = read(), m = read();
while (n)
{
memset(oppo, 0, sizeof(oppo));
fo(i, 1, n)
{
int x = read(), y = read();
oppo[x] = y;
oppo[y] = x;
}
fo(i, 1, m)a[i] = read(), b[i] = read();
int l = 0,r = m,mid=(l+r)/2+1;
while (r!=l)
{
if (check(mid)) l = mid ;
else r = mid - 1;
mid = (l + r) / 2+1;
}
printf("%d\n", l);
n = read(), m = read();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: