poj 2296

第一道2-SAT,做的挺纠结的主要是添加边的时候不细心,导致各种错误,检查了n遍终于A了。

2-SAT问题就是一组布尔变量x,分别代表两种对立的选择。还有一组变量之间的或关系的约束条件。看能否给这些变量赋值,使最后赋值的结果能够满足约束条件。

用2-SAT解决关键问题,就是确定变量及其取值所代表的的含义,还有约束条件或关系的确立。我总结了一种方法来确定或关系,就是先写出不满足题目约束条件的与关系,然后再取或关系得到需满足的或关系。比如xi和xj不能同时取1,也就是最后xi和xj的赋值不能够使(xi与xj)==1,也就是必须是(xi与xj)‘=(xi'或xj')==1,从而确定了xi'或xj'==1这一关系,就是xi取0或xj取0这一约束关系。

对于本题,每个点用一个变量来表示,取1表示向上确定正方形,0表示向下确定正方形。二分答案。对于当前的mid值,确定约束条件。如果两个点之间x坐标之差的绝对值大于等于mid的话,就不要考虑关于这两个点的约束条件,因为不管这么取,他俩互不影响,肯定不会相交,对于小于mid的,根据y坐标情况确定约束条件,总共有3种情况,具体代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#define LL long long
#define myabs(x) ((x)>0?(x):(-(x)))
using namespace std;
const int inf=0x3f3f3f3f;
const int maxm=100+10;
const int maxn=100*2+10;
struct Edge 
{
	int v,next;
};
struct node
{
	int x,y;
};
node p[maxm];
Edge e[maxn*maxn];
int mark[maxn];
int head[maxn],S[maxn];
int n,tot,top;
bool cmp(node a,node b)
{
	if(a.y==b.y) return a.x<b.x;
	else return a.y<b.y;
}
void addedge(int u,int v)
{
	e[tot].v=v; e[tot].next=head[u];
	head[u]=tot++;
}
int dfs(int u)
{
	if(mark[u]) return 1;
	if(mark[u^1]) return 0;
	mark[u]=1;
	int v,i;
	S[top++]=u;
	for(i=head[u];i!=-1;i=e[i].next)
	{
		v=e[i].v;
		if(!dfs(v)) return 0;
	}
	return 1;
}
int solve()
{
	int low=0,high=40000,mid;
	int i,j;
	while(low<=high)
	{
		mid=(low+high)/2;
		tot=0;
		memset(head,-1,sizeof(head));
		memset(mark,0,sizeof(mark));   //新的2-SAT,注意初始化 
		int flag=1;
		for(i=0;i<n;i++)
		{
			for(j=i+1;j<n;j++)
			{
				if(myabs(p[i].x-p[j].x)<mid)
				{
					if((p[j].y-p[i].y)<2*mid&&(p[j].y-p[i].y)>=mid)
					{
						addedge(j*2,i*2);
						addedge(i*2+1,j*2+1);
					}
					else if((p[j].y-p[i].y)<mid&&(p[j].y-p[i].y)>0)
					{
						addedge(j*2,i*2);
						addedge(i*2+1,j*2+1);
						addedge(j*2,i*2+1);
						addedge(i*2,j*2+1);
						addedge(j*2+1,i*2);
						addedge(i*2+1,j*2);
					}
					else if((p[j].y-p[i].y)==0)
					{
						addedge(j*2+1,i*2);
						addedge(i*2+1,j*2);
						addedge(j*2,i*2+1);
						addedge(i*2,j*2+1);
					}
				}
			}
		}
		for(i=0;i<n;i++)
		{
			if(!mark[i*2]&&!mark[i*2+1])
			{
				top=0;
				if(!dfs(i*2))
				{
					while(top>0) mark[S[--top]]=0;
					if(!dfs(i*2+1))
					{
						flag=0;
						break;
					}
				}
			}
		}
		if(flag) low=mid+1;
		else high=mid-1;
	}
	return low-1;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		scanf("%d",&n);
		int i;
		for(i=0;i<n;i++)
			scanf("%d%d",&p[i].x,&p[i].y);
		sort(p,p+n,cmp);
		int ans=solve();
		printf("%d\n",ans);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值