poj 2723 Get Luffy Out 二分+2-sat
2016-04-18 12:25
411 查看
题目链接
给n个钥匙对, 每个钥匙对里有两个钥匙, 并且只能选择一个。有m扇门, 每个门上有两个锁, 只要打开其中一个就可以通往下一扇门。
问你最多可以打开多少个门。
对于每个钥匙对, 如果选择了其中一个钥匙, 那么另一个就不能选。 所以加边(a, b'), (b, a')。
对于每个门, 如果不打开其中一个锁, 那么另一个锁就一定要打开。 所以加边(a', b), (b', a)。
然后二分判断就可以了。
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <complex> #include <cmath> #include <map> #include <set> #include <string> #include <queue> #include <stack> #include <bitset> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define lson l, m, rt<<1 #define mem(a) memset(a, 0, sizeof(a)) #define rson m+1, r, rt<<1|1 #define mem1(a) memset(a, -1, sizeof(a)) #define mem2(a) memset(a, 0x3f, sizeof(a)) #define rep(i, n, a) for(int i = a; i<n; i++) #define fi first #define se second typedef complex <double> cmx; typedef pair<int, int> pll; const double PI = acos(-1.0); const double eps = 1e-8; const int mod = 1e9+7; const int inf = 1061109567; const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; const int maxe = 1e5; const int maxn = 5000; struct node { int nextt, to; }e[maxe]; int n, m, num, cnt, top, deep, dfn[maxn], st[maxn], head[maxn], low[maxn], s[maxn], instack[maxn]; pll a[maxn], b[maxn]; void add(int u, int v) { e[num].to = v, e[num].nextt = head[u], head[u] = num++; } void tarjan(int u) { dfn[u] = low[u] = ++deep; instack[u] = 1; st[++top] = u; for(int i = head[u]; ~i; i = e[i].nextt) { int v = e[i].to; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (instack[v]) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { int v; cnt++; do { v = st[top--]; instack[v] = 0; s[v] = cnt; } while(u != v); } } void init() { mem1(head); mem(instack); mem(dfn); mem(s); num = deep = top = cnt = 0; } int check(int x) { init(); for(int i = 0; i < x; i++) { add(b[i].fi<<1|1, b[i].se<<1); add(b[i].se<<1|1, b[i].fi<<1); } for(int i = 0; i < n; i++) { add(a[i].fi<<1, a[i].se<<1|1); add(a[i].se<<1, a[i].fi<<1|1); } for(int i = 0; i < n<<2; i++) { if(!dfn[i]) tarjan(i); } /*for(int i = 0; i < n<<1; i++) cout<<s[i]<<" "; cout<<endl; */for(int i = 0; i < 2*n; i++) { if(s[i<<1] == s[i<<1|1]) return 0; } return 1; } int main() { while(~scanf("%d%d", &n, &m)) { if(n+m==0) break; for(int i = 0; i < n; i++) { scanf("%d%d", &a[i].fi, &a[i].se); } for(int i = 0; i < m; i++) { scanf("%d%d", &b[i].fi, &b[i].se); } int l = 0, r = m, ans; while(l <= r) { int mid = l+r>>1; if(check(mid)) { l = mid+1; ans = mid; } else { r = mid-1; } } printf("%d\n", ans); } return 0; }
相关文章推荐
- 排序算法---直接插入排序算法
- Centos7 安装Redis和Hiredis
- 剑指offer(十四)之调整数组顺序使奇数位于偶数前面
- Scala for the Impatients---(1)Basics
- Selenium自动化测试视频教程(Java版)
- C++中Static作用和使用方法
- 简单介绍java Enumeration
- 跳过授权表登录后使用insert into创建root权限用户
- Java 7新特性总结 - Java IO
- Java 7新特性总结 - Java IO
- HyperPacer脚本录制原理及常见问题解决
- linux 常用设置
- IOS唯一标示
- 团队作业二
- cd 命令的具体使用说明
- cd 命令的具体使用说明
- iOS之系统自带分享
- 《柏林的女人》
- java异常:java.lang.OutOfMemoryError: GC overhead limit exceeded
- 查看oracle 真实执行计划