ZOJ 3422 / SOJ 3883: Go Deeper
2013-10-06 00:52
288 查看
题目链接:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4106
题目大意:
有一个 0 - 1 序列。
给出若干限制,形如 a[x] + a[y] != z。
问至多可以同时满足前多少条限制。
算法:
二分答案 + 2-SAT判定合法性
建图也比较方便:
不等于1 就是两个元素要相等。不等于0 就是两个元素不能同时为0。不等于2 就是两个元素不能同时为1。
代码如下:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4106
题目大意:
有一个 0 - 1 序列。
给出若干限制,形如 a[x] + a[y] != z。
问至多可以同时满足前多少条限制。
算法:
二分答案 + 2-SAT判定合法性
建图也比较方便:
不等于1 就是两个元素要相等。不等于0 就是两个元素不能同时为0。不等于2 就是两个元素不能同时为1。
代码如下:
#include<cstdio> #include<iostream> #include<algorithm> #include<sstream> #include<cstdlib> #include<cstring> #include<string> #include<climits> #include<cmath> #include<queue> #include<vector> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; const int maxn = 500; const int maxq = 11000; int low[maxn], dep[maxn], blk[maxn]; int q1[maxq], q2[maxq], q3[maxq]; int blkn; int tot; int n, m; vector <int> mm[maxn]; stack <int> stk; void addedge(int u, int v) { mm[u].push_back(v); mm[v ^ 1].push_back(u ^ 1); } void tarjan(int u) { if(dep[u] == -1) { int tmp = low[u] = dep[u] = tot ++; stk.push(u); for(int i = 0; i < mm[u].size(); i ++) { int v = mm[u][i]; tarjan(v); tmp = min(tmp, low[v]); } low[u] = tmp; if(low[u] == dep[u]) { while(true) { int v = stk.top(); stk.pop(); blk[v] = blkn; low[v] = INT_MAX; if(u == v) { break; } } blkn ++; } } } bool check(int mid) { memset(dep, -1, sizeof(dep)); tot = blkn = 0; while(! stk.empty()) { stk.pop(); } for(int i = 0; i< 2 * n; i ++) { mm[i].clear(); } for(int i = 0; i <= mid; i ++) { if(q3[i] == 0) { addedge(q1[i] << 1, q2[i] << 1 | 1); addedge(q2[i] << 1, q1[i] << 1 | 1); } else if(q3[i] == 1) { addedge(q1[i] << 1 | 1, q2[i] << 1 | 1); addedge(q2[i] << 1 | 1, q1[i] << 1 | 1); addedge(q1[i] << 1, q2[i] << 1); addedge(q2[i] << 1, q1[i] << 1); } else { addedge(q1[i] << 1 | 1, q2[i] << 1); addedge(q2[i] << 1 | 1, q1[i] << 1); } } for(int i = 0; i < 2 * n; i ++) { tarjan(i); } for(int i = 0; i < n; i ++) { if(blk[i << 1] == blk[i << 1 | 1]) { return false; } } return true; } int main() { int cas; scanf("%d", &cas); while(cas --) { scanf("%d %d", &n, &m); for(int i = 0; i < m; i ++) { scanf("%d %d %d", &q1[i], &q2[i], &q3[i]); } int l = 0, r = m - 1; while (l <= r) { const int mid = l + r >> 1; if (check(mid)) l = mid + 1; else r = mid - 1; } printf("%d\n", r + 1); } return 0; }
相关文章推荐
- [ZOJ 3883] Scan Code 劳民伤财+劳神+并不科学的一个 模拟题
- ZOJ 3883 Scan Code
- ZOJ 3883 Scan Code 模拟
- ZOJ1107 HDU1078 FatMouse and Cheese
- ZOJ-1041
- ZOJ 1450 HDU 3007 (最小圆覆盖)
- 题目1032:ZOJ
- zoj 1024 Calendar Game
- ZOJ 2476 Total Amount 字符串
- zoj 3326
- ZOJ 3768 Continuous Login
- zoj 1406 Jungle Roads(简单-MST)
- ZOJ 2334 Monkey King 可并堆左偏树
- Beans Game(博弈 | | DP)zoj 3057
- ZOJ 3953 Intervals
- zoj 1110 Dick and Jane
- ZOJ-3167
- ZOJ 1456 Minimum Transport Cost
- ZOJ2256 Mincost
- zoj 1838 Crypt Kicker II