POJ 3207
题意:平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边, 比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。 给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边, 使这些边都不相交。 思路:对于每条Link,要么在圆外,要么在圆内,且不可同时满足, 只能两者取一,判断这M条Link是否合法,也就是M条Link不冲突, 这就是典型的2-sat问题了。 将每条Link i 看做一个点,如果Link在圆内, 则选做i ,如果在圆外, 则选做i'。对于两条线(i,j) ,如果i,j不能同时 在圆内,也就可以推出两者不能同时在圆外,这个证明很容易,读者可 以自行证明。i, j不能同时在圆内,则有边(i, j') 、(j ,i')、(i',j)、(j' ,i) (这是由2-sat的构图方式决定的,具体可以看《由对称性解2-SAT问题》 这篇论文)。建图完了之后,本题就是判断2-sat问题是否有解, 先求原图的强连通分量,并缩点,(这里我们称:(i,i')属于同一组), 判断是否存在(i,i')属于同一组,若存在,则不可能,若不存在则可能。
C++代码一
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #define MAXN 1005 #define MAXM 2000005 #define INF 1000000000 using namespace std; int n, m, e, head[MAXN]; int dfn[MAXN], low[MAXN], index, instack[MAXN], scc; int top, st[MAXN], fa[MAXN]; int x[MAXN], y[MAXN]; struct Edge { int v, next; }edge[MAXM]; void init() { e = index = scc = top = 0; memset(dfn, 0, sizeof(dfn)); memset(instack, 0, sizeof(instack)); memset(head, -1, sizeof(head)); } void insert(int x, int y) { edge[e].v = y; edge[e].next = head[x]; head[x] = e++; } void tarjan(int u) { int v; instack[u] = 1; st[++top] = u; dfn[u] = low[u] = ++index; for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if(instack[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { scc++; do { v = st[top--]; instack[v] = 0; fa[v] = scc; }while(v != u); } } void build() { for(int i = 1; i <= m; i++) { scanf("%d%d", &x[i], &y[i]); x[i]++; y[i]++; if(x[i] > y[i]) swap(x[i], y[i]); } for(int i = 1; i <= m; i++) for(int j = i + 1; j <= m; j++) //通过判断得出 两条线的关系,如果通过判断只能一条在内一条在外,就连边 if((x[i] <= x[j] && y[i] >= x[j] && y[i] <= y[j]) || (x[i] >= x[j] && x[i] <= y[j] && y[i] >= y[j])) { insert(i, j + m); insert(j, i + m); insert(i + m, j); insert(j + m, i); } n = 2 * m; } bool check() { for(int i = 1; i <= m; i++) if(fa[i] == fa[i + m]) return false; return true; } void solve() { for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); if(check()) printf("panda is telling the truth... "); else printf("the evil panda is lying again "); } int main() { scanf("%d%d", &n, &m); init(); build(); solve(); return 0; }
C++代码二
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef double db; typedef long long ll; typedef unsigned long long ull; const int nmax = 1e5 + 7; const int INF = 0x3f3f3f3f; const ll LINF = 0x3f3f3f3f3f3f3f3f; const ull p = 67; const ull MOD = 1610612741; int n, m, cnt; typedef pair<int , int > pii; pii line[nmax]; struct edge { int to, nxt; }; struct graph { int tot, head[nmax]; edge e[(int)1e6 + 7]; void init() { tot = 0; memset(head, -1, sizeof head); } void add_edge(int u, int v) { e[tot].to = v; e[tot].nxt = head[u]; head[u] = tot ++; } }g; inline bool checkcross(pii a, pii b) { if(a.first <= b.first && a.second >= b.first && a.second <= b.second) return true; else if(b.first <= a.first && b.second >= a.first && b.second <= a.second) return true; else if(a.first >= b.first && a.first <= b.second && a.second >= b.second) return true; else if(b.first >= a.first && b.first <= a.second && b.second >= a.second) return true; else return false; } int dfn[nmax], low[nmax], dfs_clock, color[nmax], scc; int ss[nmax], st; bool instack[nmax]; void tarjan(int u, const graph & g) { dfn[u] = low[u] = ++dfs_clock; ss[st++] = u; instack[u] = true; for(int i = g.head[u]; i != -1; i = g.e[i].nxt) { int v = g.e[i].to; if(!dfn[v]) { tarjan(v, g); low[u] = min(low[u], low[v]); } else if (instack[v]) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { scc++; int tmp; while(true) { tmp = ss[--st]; color[tmp] = scc; instack[tmp] = false; if(tmp == u) break; } } } bool check() { for(int i = 1; i <= m; ++i) { if(color[i] == color[i+m]) return false; } return true; } void init() { memset(dfn, 0, sizeof dfn); memset(low, 0, sizeof low); memset(color, 0, sizeof color); // memset(instack, 0, sizeof instack); scc = dfs_clock = st; g.init(); } int main(){ while(scanf("%d %d", &n, &m) != EOF) { init(); int a, b; for(int i = 1; i <= m; ++i) { scanf("%d %d", &a, &b); if(a < b) { line[i].first = a; line[i].second = b; } else { line[i].first = b; line[i].second = a; } } for(int i = 1; i <= m ;++i) { for(int j = i + 1; j <= m; ++j) { if(checkcross(line[i], line[j])) { g.add_edge(i, j + m); g.add_edge(i + m, j); g.add_edge(j, i + m); g.add_edge(j + m, i); } } } for(int i = 1; i <= 2 * m; ++i) { if(!dfn[i]) tarjan(i, g); } if(check()) { printf("panda is telling the truth... "); } else { printf("the evil panda is lying again "); } } return 0; }