您的位置:首页 > 其它

BZOJ 1997: [Hnoi2010]Planar|2-SAT|二分图染色

2016-01-07 09:05 351 查看
一道比较奇怪的题

用二分图染色和2-SAT都可以建模

想了一下为什么

二分图染色是找出矛盾的关系连边

2-SAT是找出“必须”的关系连边

而此题恰好都满足

--------------------------------------------------

2-SAT做法:

一组边a,b在环构成的圆内相交 那么在圆外的a‘,b'也相交

”必须“关系有 a-->b' a'-->b b-->a b'-->a

直接连边就可以了然后tarjan判断

--------------------------------------------------

二分图染色做法:

引用上面的a,b,a',b'

矛盾关系就是 a-->a' b-->b' a-->b a'-->b'

两种算法的复杂度是一样的然后用二分图染色的话,常数会稍小点

下面贴代码

2-SAT 124ms

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<iostream>
using namespace std;
int sc()
{
	int i=0; char c=getchar();
	while( c>'9' || c<'0' ) c=getchar();
	while( c>='0'&& c<='9') i=i*10+c-'0',c=getchar();
	return i;
}
int u[11111],v[11111];
int head[1888],nxt[1222222],lst[1222222];
int dfn[1888],low[1888],st[1888],vis[1888],bl[1888];
int num[222],pos[222];
int n,m,total,tot,cnt,scc,top;
void insert(int x,int y)
{
	lst[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
void tarjan(int x)
{
	vis[x]=1; st[++top]=x;
	dfn[x]=low[x]=++cnt;
	for(int i=head[x]; i; i=nxt[i])
	{
		if(vis[lst[i]]) low[x]=min(low[x],dfn[lst[i]]);
		else if(!dfn[lst[i]])
		{
			tarjan(lst[i]);
			low[x]=min(low[x],low[lst[i]]);
		}
	}
	if(dfn[x]==low[x])
	{
		int k=0; scc++;
		while(k!=x)
		{
			k=st[top--];
			bl[k]=scc;
			vis[k]=0;
		}
	}
}
int main()
{
	int Q=sc();
	while(Q--)
	{
		memset(head,0,sizeof(head));
		memset(dfn,0,sizeof(dfn));
		int flag=0; total=tot=cnt=top=scc=0;
		n=sc(); m=sc();
		for(int i=1; i<=m; i++) u[i]=sc(),v[i]=sc();
		for(int i=1; i<=n; i++) num[i]=sc(),pos[num[i]]=i;
		if(m>3*n-6) {puts("NO");continue;}
		for(int i=1; i<=m; i++)
		{
			u[i]=pos[u[i]],v[i]=pos[v[i]];
			if(u[i]>v[i]) swap(u[i],v[i]);
			if(v[i]-u[i]==1||v[i]-u[i]==n-1) continue;
			u[++total]=u[i],v[total]=v[i];
		}
		for(int i=1; i<=total; i++)
		    for(int j=i+1; j<=total; j++)
		    if((u[i]<u[j]&&u[j]<v[i]&&v[i]<v[j])||(u[j]<u[i]&&u[i]<v[j]&&v[j]<v[i]))
		    {
		    	insert(2*i,2*j+1);
		    	insert(2*i+1,2*j);
		    	insert(2*j,2*i+1);
		    	insert(2*j+1,2*i);
		    }
		for(int i=2; i<=2*total+1; i++)
		    if(!dfn[i]) tarjan(i);
		for(int i=1; i<=total; i++)
		    if(bl[i*2]==bl[i*2+1]){flag=1,puts("NO");break;}
		if(!flag) puts("YES");
	}
	return 0;
}


二分图染色 100ms

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<iostream>
using namespace std;
int sc()
{
	int i=0; char c=getchar();
	while( c>'9' || c<'0' ) c=getchar();
	while( c>='0'&& c<='9') i=i*10+c-'0',c=getchar();
	return i;
}
int u[11111],v[11111];
int head[1888],nxt[1222222],lst[1222222];
int col[1888];
int num[222],pos[222];
int n,m,total,tot;
void insert(int x,int y)
{
	lst[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
bool color(int x,int f)
{
	col[x]=f;
	for(int i=head[x]; i; i=nxt[i])
	{
		if(!col[lst[i]])
		{
			if(!color(lst[i],f^1)) return 0;
		}
		else  if(col[lst[i]]==col[x]) return 0;
	}
	return 1;
}	
int main()
{
	int Q=sc();
	while(Q--)
	{
		memset(head,0,sizeof(head));
		memset(col,0,sizeof(col));
		int flag=0; total=tot=0;
		n=sc(); m=sc();
		for(int i=1; i<=m; i++) u[i]=sc(),v[i]=sc();
		for(int i=1; i<=n; i++) num[i]=sc(),pos[num[i]]=i;
		if(m>3*n-6) {puts("NO");continue;}
		for(int i=1; i<=m; i++)
		{
			u[i]=pos[u[i]],v[i]=pos[v[i]];
			if(u[i]>v[i]) swap(u[i],v[i]);
			if(v[i]-u[i]==1||v[i]-u[i]==n-1) continue;
			u[++total]=u[i],v[total]=v[i];
		}
		for(int i=1; i<=total; i++)
		    for(int j=i+1; j<=total; j++)
		    if((u[i]<u[j]&&u[j]<v[i]&&v[i]<v[j])||(u[j]<u[i]&&u[i]<v[j]&&v[j]<v[i]))
		    {
		    	insert(2*i,2*j);
		    	insert(2*j,2*i);
		    	insert(2*i+1,2*j+1);
		    	insert(2*j+1,2*i+1);
		    }
		for(int i=1; i<=total; i++) insert(2*i,2*i+1),insert(2*i+1,2*i);
		for(int i=2; i<=total*2+1; i++)
		    if(!col[i]&&!color(i,2)){flag=1;break;}
		if(flag)puts("NO");else puts("YES");
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: