题目链接:
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; }