zoj3422Go Deeper(2-sat + 二分)
题目大意:
go(int dep, int n, int m) begin output the value of dep. if dep < m and x[a[dep]] + x[b[dep]] != c[dep] then go(dep + 1, n, m) end
读上面程序段,yy出函数功能。数组a,b,c长度为m,x长度为n。数组a,b中元素范围[0,n - 1],数组c元素为0或1或2。x数组元素为1或0。求能输出的最大的m。
题目分析:2-sat,还是比较裸的吧。要求最大的m,所以对长度m二分。
详情请见代码:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 405; const int M = 10005; struct node { int to,next; }g[M]; int head[N],stack1[N],stack2[N],vis[N],scc[N]; int n,m,num; bool flag; int a[M],b[M],c[M]; void init() { memset(head,-1,sizeof(head)); flag = true; memset(vis,0,sizeof(vis)); memset(scc,0,sizeof(scc)); stack1[0] = stack2[0] = 0; num = 0; } void build(int s,int e) { g[num].to = e; g[num].next = head[s]; head[s] = num ++; } void dfs(int cur,int &sig,int &cnt) { if(flag == false) return; vis[cur] = ++ sig; stack1[++stack1[0]] = cur; stack2[++stack2[0]] = cur; for(int i = head[cur];~i;i = g[i].next) { if(!vis[g[i].to]) dfs(g[i].to,sig,cnt); else { if(scc[g[i].to] == 0) while(vis[stack2[stack2[0]]] > vis[g[i].to]) stack2[0] --; } } if(stack2[stack2[0]] == cur) { stack2[0] --; cnt ++; do { scc[stack1[stack1[0]]] = cnt; if(scc[stack1[stack1[0]]^1] == cnt) { flag = false; return; } }while(stack1[stack1[0] --] != cur); } } void Gabow() { int i,sig,cnt; sig = cnt = 0; for(i = 0;i < n + n && flag;i ++) if(!vis[i]) dfs(i,sig,cnt); } void solve() { int l,r,mid; int ans,i; l = 0;r = m; while(l <= r) { mid = (l + r)>>1; init(); for(i = 0;i < mid;i ++) { int u = a[i]<<1; int v = b[i]<<1; if(c[i] == 0)// !=0 { build(u,v^1); build(v,u^1); } if(c[i] == 1)// != 1 { build(u,v); build(v,u); build(u^1,v^1); build(v^1,u^1); } if(c[i] == 2)// != 2 { build(u^1,v); build(v^1,u); } } Gabow(); if(flag) { ans = mid; l = mid + 1; } else r = mid - 1; } printf("%d\n",ans); } int main() { int i,t; scanf("%d",&t); while(t --) { scanf("%d%d",&n,&m); for(i = 0;i < m;i ++) scanf("%d%d%d",&a[i],&b[i],&c[i]); solve(); } return 0; }