poj3207-Ikki's Story IV - Panda's Trick
\(n\)个数字按顺序排成一圈,给出\(m\)条连线\((a,b)\),连线可以在圆内或圆外,问是否可能做到所有连线只在顶点上相交。
分析
一个好像平面图判定的题~
两条线\((a,b)\),\((c,d)\)相交的条件是\(a<c<b<d\),如果他们在圆内会相交,那么他们在圆外也会相交,也就是说,这两条线是不能同时在圆内或圆外的。一条线在圆内或圆外,有两种取值,可以看成是一个2-SAT问题。发现数据范围不大,所以直接对所有的连线两两判定一下,连边表示他们不共存就好了。注意不共存的连边是\(a\ne b\),等价于\(a\oplus b=true\)。
其实这个题还可以用二分图染色做。观察上面的连边,可以发现,这里的条件都是某两条线的不共存,所以我们可以把圆内和圆外看成二分图的左边和右边,不共存的连边,然后只要判断这个图是不是一个二分图即可。
代码
2-SAT
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=1005;
const int maxm=maxn*maxn;
int dfn[maxn],low[maxn],id[maxn],dft=0,sta[maxn],top=0,col=0;
bool ins[maxn];
struct line {
int x,y;
void sort() {
if (x>y) swap(x,y);
}
} a[maxn];
bool cross(line &a,line &b) {
return a.x<b.x && b.x<a.y && a.y<b.y;
}
struct edge {
int v,nxt;
};
struct graph {
edge e[maxm];
int h[maxn],tot;
graph ():tot(0) {}
void add(int u,int v) {
e[++tot]=(edge){v,h[u]};
h[u]=tot;
}
void Tarjan(int x) {
dfn[x]=low[x]=++dft;
sta[++top]=x;
ins[x]=true;
for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (!dfn[v]) {
Tarjan(v);
low[x]=min(low[x],low[v]);
} else if (ins[v]) low[x]=min(low[x],dfn[v]);
if (low[x]==dfn[x]) {
++col;
do id[sta[top--]]=col; while (sta[top+1]!=x);
}
ins[x]=false;
}
bool run(int m) {
for (int i=1;i<=m;++i) if (id[i]==id[i+m]) return false;
return true;
}
} A;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
int n=read(),m=read();
for (int i=1;i<=m;++i) a[i].x=read(),a[i].y=read(),a[i].sort();
for (int i=1;i<=m;++i) for (int j=i+1;j<=m;++j) if (cross(a[i],a[j])) {
A.add(i,j+m),A.add(j,i+m),A.add(i+m,j),A.add(j+m,i);
}
for (int i=1;i<=(m<<1);++i) if (!dfn[i]) A.Tarjan(i);
puts(A.run(m)?"panda is telling the truth...":"the evil panda is lying again");
return 0;
}
二分图染色
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=1005;
const int maxm=maxn*maxn;
int col[maxn];
bool flag=true;
struct line {
int x,y;
void sort() {
if (x>y) swap(x,y);
}
} a[maxn];
bool cross(line &a,line &b) {
return a.x<b.x && b.x<a.y && a.y<b.y;
}
struct edge {
int v,nxt;
};
struct graph {
edge e[maxm];
int h[maxn],tot;
graph ():tot(0) {}
void add(int u,int v) {
e[++tot]=(edge){v,h[u]};
h[u]=tot;
}
bool dye(int x,int c) {
col[x]=c;
for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) {
if (col[v]==(c^1)) continue;
if (col[v]==c) return false;
if (!dye(v,c^1)) return false;
}
return true;
}
} A;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
int n=read(),m=read();
for (int i=1;i<=m;++i) a[i].x=read(),a[i].y=read(),a[i].sort();
for (int i=1;i<=m;++i) for (int j=i+1;j<=m;++j) if (cross(a[i],a[j])) A.add(i,j),A.add(j,i);
for (int i=1;i<=m;++i) if (!col[i] && !A.dye(i,2)) {
flag=false;
break;
}
puts(flag?"panda is telling the truth...":"the evil panda is lying again");
return 0;
}