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;
}
posted @ 2017-04-21 08:34  permui  阅读(193)  评论(0编辑  收藏  举报