poj3207 2-SAT

来源:互联网 发布:instanceof php 编辑:程序博客网 时间:2024/06/07 07:01

题意:

一个圆上顺时针放着n个点,现在要连m条边,每条边可以从圆的内部连也可以从圆的外部连。

保证每个点最多连1条边,问是否能使所有的边都不相交。


思路:

典型的2-sat问题。

建图:对于一条边i,在圆内记为i,在圆外记为i'

设边i连接点A,B,边j连接点C,D。i与j在圆内是否相交就是线段AB与线段CD是否相交,用坐标判断一下。

可以证明,如果i与j在圆内不能共存,则在圆外也一定不能共存,即:

i在圆内,则j一定在圆外,建边i->j'

i在圆外,则j一定在圆内,建边i'->j

j在圆内,则i一定在圆外,建边j->i'

j在圆外,则i一定在圆内,建边j'->i


然后用2-sat判断是否可行。


代码(1868K,110MS):

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <vector>#include <utility>#include <stack>using namespace std;struct Pair{int x, y;Pair() {}Pair(int a, int b) : x(a), y(b) {}};int n, m, t;int cnt, num;vector<int> edges[1002];Pair p[502];stack<int> s;int dfn[1002];int low[1002];int vis[1002];int col[1005];void dfs(int u) {s.push(u);vis[u] = 1;dfn[u] = low[u] = ++cnt;for (int i = 0; i < edges[u].size(); i++) {int v = edges[u][i];if (!dfn[v]) {dfs(v);low[u] = min(low[u], low[v]);} else if (vis[v])low[u] = min(low[u], dfn[v]);}if (low[u] == dfn[u]) {num++;do {t = s.top();s.pop();vis[t] = 0;col[t] = num;} while (t != u);}}void tarjan() {cnt = num = 0;while (!s.empty()) s.pop();memset(dfn, 0, sizeof(dfn));memset(low, 0, sizeof(low));memset(vis, 0, sizeof(vis));memset(col, 0, sizeof(col));for (int i = 1; i <= m << 1; i++)if (!dfn[i]) dfs(i);}bool solve() {tarjan();for (int i = 1; i <= m; i++)if (col[i] == col[i + m]) return false;return true;}int main() {while (~scanf("%d %d", &n, &m)) {for (int i = 1; i <= m << 1; i++)edges[i].clear();int a, b;for (int i = 1; i <= m; i++) {scanf("%d %d", &a, &b);if (a > b) swap(a, b);p[i] = Pair(a, b);}for (int i = 1; i <= m; i++) {for (int j = i + 1; j <= m; j++) {if (p[j].x >= p[i].x && p[j].x <= p[i].y && p[j].y >= p[i].y|| p[j].y >= p[i].x && p[j].y <= p[i].y && p[j].x <= p[i].x) {edges[i].push_back(j + m);edges[j].push_back(i + m);edges[i + m].push_back(j);edges[j + m].push_back(i);}}}bool ans = solve();if (ans) printf("panda is telling the truth...\n");else printf("the evil panda is lying again");}return 0;}


0 0
原创粉丝点击