题意:一个圆上依次分布着一些点,距离不重要。然后给你一些点对,要你将这两个点连线,问存不存在一种方案,使得在所有线段都不交叉的情况下,能连完所有线段。显然线段不是在圆内连线就是在圆外连线。
样例数据如下:
4个点两条线,满足条件的方案有好2种,如下图,所以输出"panda is telling the truth..."4 2 0 1 3 2
每个点有两种状态,内连或外连,所以只要建图以后判断同一个点是否既必须内连又必须外连即可。
所以冲突的条件就是
找到冲突边以后建图,我用的是邻接表,要注意点对是2i,2i+1,2j,2j+1。bool conflict(int a, int b, int c, int d) { if(c < a && d > a && d < b) // c<a与d>a好写,千万不要遗漏d<b的条件 return true; if(c > a && c < b && d > b) return true; return false; }
建图并tarjan以后,只要判断同一个点是否又得内连又得外连(无解)即可。struct point { vector<int> v; }pt[maxn*2];
for(int i = 0; i < n - 1; i++) {
for(int j = i+1; j < n; j++) { if(conflict(tt[i].s, tt[i].t, tt[j].s, tt[j].t)) { pt[i*2].v.push_back(j*2+1); pt[j*2+1].v.push_back(i*2); pt[i*2+1].v.push_back(j*2); pt[j*2].v.push_back(i*2+1); } } }
for(int i = 0; i < n; i++) { if(belong[i*2] == belong[i*2+1]) { flag = 1; break; } }
完整代码如下:
另外由于这道题比较特别,矛盾边为i j和i' j'#include<iostream> #include<cstdio> #include<vector> using namespace std; #define maxn 1010 int n, m; struct point { vector<int> v; }pt[maxn*2]; struct node { int s; int t; }tt[maxn]; int index, stacktop, cnt; int dfn[maxn*2], low[maxn*2]; int instack[maxn*2], stap[maxn*2]; int belong[maxn*2]; int min(int a, int b) { return a < b ? a : b; } bool conflict(int a, int b, int c, int d) { if(c < a && d > a && d < b) return true; if(c > a && c < b && d > b) return true; return false; } void Clear() { index = stacktop = cnt = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(instack, false, sizeof(instack)); memset(belong, 0, sizeof(belong)); } void tarjan(int u) { dfn[u] = low[u] = ++index; instack[u] = true; stap[++stacktop] = u; for(int i = 0; i < pt[u].v.size(); i++) { if(!dfn[i]) { tarjan(i); low[u] = min(low[u], low[i]); } else if(instack[i]) { low[u] = min(low[u], dfn[i]); } } if(low[u] == dfn[u]) { cnt++; int v; do { v = stap[stacktop--]; instack[v] = false; belong[v] = cnt; }while(v != u); } } int main() { while(~scanf("%d%d", &n, &m)) { for(int i = 0; i < m; i++) { scanf("%d%d", &tt[i].s, &tt[i].t); } for(int i = 0; i < n - 1; i++) { for(int j = i+1; j < n; j++) { if(conflict(tt[i].s, tt[i].t, tt[j].s, tt[j].t)) { pt[i*2].v.push_back(j*2+1); pt[j*2+1].v.push_back(i*2); pt[i*2+1].v.push_back(j*2); pt[j*2].v.push_back(i*2+1); } } } Clear(); for(int i = 0; i < 2*n; i++) { if(!dfn[i]) tarjan(i); } int flag = 0; for(int i = 0; i < n; i++) { if(belong[i*2] == belong[i*2+1]) { flag = 1; break; } } if(flag) printf("the evil panda is lying again\n"); else printf("panda is telling the truth...\n"); } return 0; }
#include<iostream> using namespace std; struct node { int s; int t; }line[600]; int father[2010]; bool judge(int a, int b, int c, int d) { if(c < b && c > a && d > b) return true; if(c < a && d > a && d < b) return true; return false; } int find(int x) { if(x == father[x]) return x; return father[x] = find(father[x]); } int main() { int n, m; int x, y; while(~scanf("%d%d", &n, &m)) { for(int i = 0; i < m; i++) { scanf("%d%d", &line[i].s, &line[i].t); } for(int i = 0; i < n; i++) father[i] = i; for(int i = 0; i < m-1; i++) { for(int j = i+1; j < m; j++) { if(judge(line[i].s, line[i].t, line[j].s, line[j].t)) { x = find(2*i); y = find(2*j+1); father[x] = y; x = find(2*i+1); y = find(2*j); father[x] = y; } } } int flag = 0; for(int i = 0; i < m; i++) { if(find(2*i) == find(2*i+1)) { flag = 1; break; } } if(flag) printf("the evil panda is lying again\n"); else printf("panda is telling the truth...\n"); } return 0; }