UVA11294 Wedding

来源:互联网 发布:怎么找文献的数据 编辑:程序博客网 时间:2024/05/01 11:45

微微发亮的传送门

2-SAT问题输出可行解

可以把一对夫妇当成一个节点,然后拆点的话,h和w分别为真和假,然后直接按照题目中说的建图染色即可

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <stack>#include <queue>using namespace std;const int maxn = 222;int pre[maxn], sccno[maxn], lowlink[maxn], scc_cnt, dfs_clock, ha[maxn];int col[maxn], ind[maxn];vector<int> G[maxn], g[maxn];stack<int> S;queue<int> que;void add_clause(int x, int xval, int y, int yval){x = x * 2 + xval;y = y * 2 + yval;G[x ^ 1].push_back(y);G[y ^ 1].push_back(x);}void dfs(int u){      pre[u] = lowlink[u] = ++dfs_clock;      S.push(u);      for (int i = 0; i < G[u].size(); i++){          int v = G[u][i];          if (!pre[v]){              dfs(v);              lowlink[u] = min(lowlink[u], lowlink[v]);          }          else if (!sccno[v])              lowlink[u] = min(lowlink[u], pre[v]);      }      if (lowlink[u] == pre[u]){          scc_cnt += 1;          for (;;){              int x = S.top(); S.pop();              sccno[x] = scc_cnt;              if (x == u) break;          }      }  }  void tarjan(int n){      dfs_clock = scc_cnt = 0;      memset(pre, 0, sizeof(pre));      memset(sccno, 0, sizeof(sccno));      memset(lowlink, 0, sizeof(lowlink));      for (int i = 0; i < n; i++)          if (!pre[i]) dfs(i);  }int n, m, x, y, a, b;char c1, c2;void topsort(){ while(!que.empty())  {          int u = que.front();          que.pop();          int size = g[u].size();          if(!col[u]) col[u] = 1, col[ha[u]] = 2;          for(int i = 0; i < size; i++){              int v = g[u][i];              ind[v]--;              if(ind[v] == 0) que.push(v);          }      }  }int main(){while(~scanf("%d%d", &n, &m)){if (!n && !m) break;for (int i = 0; i <= n * 2; i++){G[i].clear(); g[i].clear();}for (int i = 0; i < m; i++){scanf("%d%c %d%c", &x, &c1, &y, &c2);a = c1 == 'h' ? 0 : 1;b = c2 == 'h' ? 0 : 1;add_clause(x, a, y, b);}G[0].push_back(1);tarjan(2 * n);memset(ha, 0, sizeof(ha));bool f = 1;for (int i = 0; i < n; i++)if (sccno[2 * i] == sccno[2 * i + 1]){f = 0; break;}else ha[sccno[2 * i]] = sccno[2 * i + 1], ha[sccno[2 * i + 1]] = sccno[2 * i];if (!f){printf("bad luck\n"); continue;}memset(ind, 0, sizeof(ind));for (int i = 0; i < 2 * n; i++)for (int j = 0; j < G[i].size(); j++){int v = G[i][j];if (sccno[i] != sccno[v]){g[sccno[v]].push_back(sccno[i]); ind[sccno[i]] += 1;}}while (!que.empty()) que.pop();for (int i = 1; i <= scc_cnt; i++)if (ind[i] == 0) que.push(i);memset(col, 0, sizeof(col));topsort();for (int i = 2; i < 2 * n; i += 2){if (i != 2) printf(" ");if (col[sccno[i]] == col[sccno[0]]) printf("%dw", i / 2);else printf("%dh", i / 2);}printf("\n");}return 0;}

另附一佳哥版本的解法,速度竟然比一般解法快诶……佳哥不愧把算法当艺术的大牛……

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int maxn = 222;struct TowSAT{vector<int> G[maxn];bool mark[maxn];int S[maxn], c, n;bool dfs(int x){if (mark[x ^ 1]) return 0;if (mark[x]) return 1;mark[x] = 1;S[c++] = x;for (int i = 0; i < G[x].size(); i++)if (!dfs(G[x][i])) return 0;return 1;}void init(int n){this -> n = n;for (int i = 0; i <= n; i++)G[i].clear();memset(mark, 0, sizeof(mark));}void add_clause(int x, int xval, int y, int yval){x = x * 2 + xval;y = y * 2 + yval;G[x ^ 1].push_back(y);G[y ^ 1].push_back(x);}bool solve(){for (int i = 0; i < n * 2; i += 2)if (!mark[i] && !mark[i + 1]){c = 0;if (!dfs(i)){while(c > 0) mark[S[--c]] = 0;if (!dfs(i + 1)) return 0;}}return 1;}};int n, m, x, y, a, b;char c1, c2;TowSAT solver;int main(){while(~scanf("%d%d", &n, &m)){if (!n && !m) break;solver.init(2 * n);for (int i = 0; i < m; i++){scanf("%d%c %d%c", &x, &c1, &y, &c2);a = c1 == 'h' ? 0 : 1;b = c2 == 'h' ? 0 : 1;solver.add_clause(x, a, y, b);}solver.G[0].push_back(1);if (!solver.solve()) printf("bad luck");else for (int i = 2; i < 2 * n; i += 2){if (i != 2) printf(" ");if (solver.mark[i] == solver.mark[0]) printf("%dw", i / 2);else printf("%dh", i / 2);}printf("\n");}return 0;}


原创粉丝点击