http://hi.baidu.com/joy32812/item/8d2c066065a2e92c68105b12
http://www.cnblogs.com/ambition/archive/2011/07/30/2-sat.html 这个比较推荐照这个刷,这个2-sat就基本差不多了
HDU 3062 Party 【裸题】 模版题
#include <cstdio> #include <cstring> using namespace std; const int maxn=2000+123; const int maxm=2000000+123; struct Edge{ int v, next; }edge[maxm]; int head[maxn], cnt; void addedge(int u, int v) { edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } void init() { memset (head, -1, sizeof(head)); cnt=0; } inline void add(int u, int v) { addedge(u, v^1); addedge(v, u^1); } int id[maxn], pre[maxn], low[maxn], s[maxn], cnt0, scnt, stop; void dfs(int u, int n) { int t, minc=low[u]=pre[u]=cnt0++; s[stop++]=u;/// 存入栈中。 for (int p=head[u]; ~p; p=edge[p].next) { const int &v=edge[p].v; if(-1==pre[edge[p].v])dfs(v, n); if(low[v]<minc)minc=low[v]; } if(minc<low[u]) { low[u]=minc; return; } for (; id[t=s[--stop]]=scnt, low[t]=n, t!=u;); scnt++; } void tarjan(int n) { memset (pre, 0xff, sizeof(pre)); cnt0=scnt=stop=0; for (int i=0; i<n; ++i) if(-1 == pre[i])dfs(i, n); } bool Two_sat(int n) { tarjan(n); for (int i=0; i<n; i+=2) { ///printf("%d %d\n", id[i], id[i|1]); if(id[i]==id[i|1])return false; } return true; } int main() { int n, m; while (~scanf("%d%d", &n, &m)) { init(); for (int i=0; i<m; ++i) { int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d); int u=a*2+c, v=b*2+d; add(u, v); ///printf("u=%d sv=%d\nv=%d sv=%d\n", u, v^1, v, u^1); // addedge(u, v^1); // addedge(v, u^1); } puts(Two_sat(2*n)?"YES":"NO"); } return 0; } /* 2 1 0 1 1 1 2 2 0 1 1 1 0 1 0 1 */
POJ 3678 Katu Puzzle 接近裸题
vector <int> G[maxn]; inline void add(int u, int v) { ///printf("u=%d v'=%d\nv=%d u'=%d\n", u, v^1, v, u^1); G[u].push_back(v^1); G[v].push_back(u^1); } int low[maxn], pre[maxn], S[maxn], Stop, scnt, cnt0, id[maxn]; void dfs(int u, int n) { int minc=low[u]=pre[u]=cnt0++; S[Stop++]=u; int sz=G[u].size(); // for_each(G[u].begin(), G[u].end(), printf);??? for (int i=0; i<sz; ++i) { if(-1 == pre[G[u][i]])dfs(G[u][i], n); minc=min(minc, low[G[u][i]]); } if(minc<low[u]) { low[u]=minc; return; } for (int t; id[t=S[--Stop]]=scnt, low[t]=n, t!=u; ); scnt++; } void tarjan(int n) { memset(pre, -1, sizeof(pre)); cnt0=scnt=Stop=0; for (int i=0; i<n; ++i) if(-1 == pre[i])dfs(i, n); } bool Two_sat(int n) { tarjan(2*n); for (int i=0; i<n; ++i) { ///printf("%d %d\n", id[i<<1], id[i<<1|1]); if(id[i<<1]==id[i<<1|1])return false; } return true; } int main() { int n, m; while (~scanf("%d%d", &n, &m)) { for (int i=0; i<2*n; ++i)G[i].clear(); for (int i=0; i<m; ++i) { int a, b, c; char op[10]; scanf("%d%d%d%s", &a, &b, &c, op); if(op[0]=='A') { if(c==1) { add(a<<1, b<<1);/// 0 0 add(a<<1, b<<1|1);/// 0 1 add(a<<1|1, b<<1);/// 1 0 } else add(a<<1|1, b<<1|1);/// 1 1 } if(op[0]=='O') { if(c==1) { add(a<<1, b<<1); } else { add(a<<1|1, b<<1); add(a<<1, b<<1|1); add(a<<1|1, b<<1|1); } } if(op[0]=='X') { if(c==1) { add(a<<1, b<<1); add(a<<1|1, b<<1|1); } else { add(a<<1|1, b<<1); add(a<<1, b<<1|1); } } } puts(Two_sat(n)?"YES":"NO"); } return 0; }
HDU 3622 Bomb Game 二分+构图, 还是很水的, 不过前提是看出是2sat.
3648Wedding spj的输出任意解, 这里要求输出的是除了解集之外的解, 就是0w之外的蓝色。 由于是spj,可以忽略格式。
#include <cstdio> #include <cstring> #include <vector> #include <queue> using namespace std; const int maxn=2000+123; const int maxm=2000000+123; struct Edge{ int v, next; }edge[maxm]; int head[maxn], cnt; void addedge(int u, int v) { edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } void init() { memset (head, -1, sizeof(head)); cnt=0; } inline void add(int u, int v) { addedge(u, v^1);addedge(v, u^1); } ///************tarjan*********************/// int id[maxn], pre[maxn], low[maxn], s[maxn], cnt0, scnt, stop; void dfs(int u, int n) { int t, minc=low[u]=pre[u]=cnt0++; s[stop++]=u; for (int p=head[u]; ~p; p=edge[p].next) { const int &v=edge[p].v; if(-1==pre[edge[p].v])dfs(v, n); if(low[v]<minc)minc=low[v]; } if(minc<low[u]) { low[u]=minc; return; } for (; id[t=s[--stop]]=scnt, low[t]=n, t!=u;); scnt++; } void tarjan(int n) { memset (pre, 0xff, sizeof(pre)); cnt0=scnt=stop=0; for (int i=0; i<n; ++i) if(-1 == pre[i])dfs(i, n); } /// ***********scc***************/// int deg[maxn], opp[maxn]; vector<int> G[maxn]; void getback(int n)///build the artigraph in { memset (deg, 0, sizeof(deg)); for (int i=0; i<n; ++i) G[i].clear(); for (int i=0; i<n; ++i) { opp[id[i]]=id[i^1];opp[id[i^1]]=id[i]; for (int p=head[i]; ~p; p=edge[p].next) { const int &v=edge[p].v; if(id[i]!=id[v]) { G[id[v]].push_back(id[i]); deg[id[i]]++; } } } } int color[maxn]; queue<int> Q; bool toposort(int n) { for (int i=0; i<n; ++i) if(deg[i]==0)Q.push(i); while(!Q.empty()) { int u=Q.front(); Q.pop(); if(color[u] == 0) { color[u]=1; color[opp[u]]=2; } for (int i=0; i<G[u].size(); ++i) { int v=G[u][i]; deg[v]--; if(deg[v]==0)Q.push(v); } } } bool Two_sat(int n) { tarjan(2*n); for (int i=0; i<n; i++) if(id[i<<1]==id[i<<1|1])return false; memset (opp, -1, sizeof(opp)); memset (color, 0, sizeof(color)); getback(2*n); while (!Q.empty())Q.pop();/// 先清空队列。 toposort(scnt);/// 这里是连通分量数 return true; } int main() { int n, m; while (scanf("%d%d", &n, &m), n&&m) { init(); for (int i=0; i<m; ++i) { int a, b; char c, d; scanf("%d%c %d%c", &a, &c, &b, &d); add(a*2+('h'==c), b*2+('h'==d)); } //add(0, 1); addedge(0, 1); /**找出一组可行的方案坐在0w对面, 这样加边会使0h出现在可行解中, 与他同色的当然也是这个解的其他元素**/ /// 输出的是除了0w以外的其他非解元素 if(Two_sat(n)) { for (int i=2; i<2*(n-1); ++i) if(color[id[i]]==color[id[0]])printf("%d%c ", i>>1, i&1?'h':'w'); for (int i=2*(n-1); i<2*n; ++i) if(color[id[i]]==color[id[0]])printf("%d%c \n", i>>1, i&1?'h':'w'); } else printf("bad luck\n"); } return 0; }
hdu 1814 要求输出字典序最小的方案
http://www.cppblog.com/MatoNo1/archive/2011/07/13/150766.aspx