bzoj1823 tarjan算法应用-2-sats算法

来源:互联网 发布:产品数据管理软件 编辑:程序博客网 时间:2024/06/11 14:52
//对于tarjan搞完后要求拓扑序的话只要记录每个强联通分量的出度和父亲边就好了从出度为0的开始用一个栈来保存出度为0的强联通分量;//此题不阔能爆栈,不要蛋桶的去写非递归。。。//什么问题用sat?当要二选以然后又矛盾的情况时用。能够用(a并b)交(x并y)........表示的问题就阔以用。//如在只能选a 和b 中的一个时而且必须选一个就是(a交非b)并(b交非a)化简后就是(a并b)交(非b并非a)然后就是建图转化咯。。。。//算法:看a与非a是否在同一个联通分量中如果是则无解。如何求解?搞拓扑序然后a的拓扑序在非a前a假,或者a的拓扑序在非a后a真(这里所谓的前是因为求拓扑序时是倒着求得从出度为0的点开始的。//原理:1.a->b如果a错则这个表达式是真,或者a真且b真也是。根据这个定理a为真是b以及b->x->y....后面的都是真。//2.看对称性。如果a,b在同一个联通分量中,那么非a与非b也在同一个联通分量中。所以。。自己yy吧。//写tarjan算法的时候就是根据dfs树的前向边和后向边来求。什么事dfs树?看算法导论。#include<iostream>#include<cstdio>#include<algorithm>#include<string.h>using namespace std;struct edgee{int to;};edgee edge[2001];int first[201], nextt[2001];int kind[2][201];int diantot, belong[201],edgetot=1;int isinstack[201], stack[201],state[201];int low[201], dfn[201];int dfstot,stacktop=-1,circlenum;void addedge(int from, int to){edge[edgetot].to = to;nextt[edgetot] = first[from];first[from] = edgetot;edgetot++;}void tarjan(int num){if (belong[num] != -1)return;state[num] = 1;low[num] = dfn[num] = dfstot++;stack[++stacktop] = num; isinstack[num] = 1;for (int i = first[num]; i; i = nextt[i]){int to = edge[i].to;if (state[to] == 0){tarjan(to);low[num] = min(low[num], low[to]);}else{if (isinstack[to])low[num] = min(low[num], dfn[to]);}}state[num] = 2;if (low[num] == dfn[num]){circlenum++;while (stack[stacktop] != num){int temp = stack[stacktop];isinstack[temp] = 0; belong[temp] = circlenum;stacktop--;}int temp = stack[stacktop]; isinstack[temp] = 0; belong[temp] = circlenum;stacktop--;}}int getnum(char *s){int len = strlen(s);int num = 0;for (int i = 1; i <= len - 1; i++){num = num * 10;num += s[i] - '0';}return num;}int main(){///char c[5];//c[1] = '1'; c[2] = '0'; c[3] = '\0'; //c[4] = '\0';//cout << getnum(c) << endl;int times;scanf("%d", ×);while (times--){int n, mm;scanf("%d%d", &n, &mm);for (int i = 1; i <= 2 * n + 10; i++){belong[i] = -1; state[i] = 0; first[i] = 0; if(i<=101)kind[0][i] = 0, kind[1][i] = 0;}diantot = 1; edgetot = 1; dfstot = 0; stacktop = -1; circlenum = 0; belong[0] = -1;for (int i = 0; i < mm; i++){char a[10], b[10];int kinda, kindb,numa,numb;scanf("%s%s", a, b);if (a[0] == 'h')kinda = 0; else kinda = 1;if (b[0] == 'h')kindb = 0; else kindb = 1;numa = getnum(a); numb = getnum(b);if (kind[kinda][numa] == 0)kind[kinda][numa] = diantot++; if  (kind[kinda^1][numa] == 0)kind[kinda^1][numa] = diantot++;if (kind[kindb][numb] == 0)kind[kindb][numb] = diantot++; if (kind[kindb^1][numb] == 0)kind[kindb^1][numb] = diantot++;addedge(kind[kinda ^ 1][numa], kind[kindb][numb]);addedge(kind[kindb ^ 1][numb], kind[kinda][numa]);}//for (int i = 1; i < diantot; i++)//{//cout << "from:" << i;//for (int j = first[i]; j; j = nextt[j])//cout << "to:" << " "<<edge[j].to;//cout << endl;//}for (int i = 1; i < diantot; i++){tarjan(i);//cout << i << endl;//for (int j= 1; j<= n; j++)cout << "i:" << j << " " << "m:" << kind[1][j] << " " << "h:" << kind[0][j] << " " << "belongh:" << belong[kind[0][j]] << " " << "belongm:" << belong[kind[1][j]] << endl;}bool isright = true;for (int i = 1; i <= n; i++)if ((belong[kind[0][i]] == belong[kind[1][i]]) && belong[kind[1][i]]!=-1 && belong[kind[0][i]]!=-1)isright = false;if (isright)printf("GOOD\n");elseprintf("BAD\n");}return 0;}