poj 2296 2-SAT(无矩形相交的最大边长)

来源:互联网 发布:统计贸易数据自查报告 编辑:程序博客网 时间:2024/04/30 18:07

题意:欲在平面直角坐标系上贴n个边长相同的正方形标签,要求标签不能重合。输入为n个点(给出坐标)。要求每个点是在标签的下边中点或者上边中点出,求符合题意的标签的最大边长。

思路:2-SAT+二分答案。

首先二分枚举答案。对每一对点,标签的位置由四种情况,枚举这四种情况,判断标签是否相交,如此建图。转化为tarjan算法解决的2-SAT问题。

#include <stdio.h>#include <string.h>#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))#define N 1005struct edge{int x,y,next;}e[N*N];struct point{int x,y;}p[N];int n,T,top,lo,high,mid,res,index,num,tops;int first[N],dfn[N],low[N],strong[N],stack[N];void init(){top = index = num = 0;tops = -1;memset(first,-1,sizeof(first));memset(dfn,-1,sizeof(dfn));memset(strong,0,sizeof(strong));}void add(int x,int y){e[top].y = y;e[top].next = first[x];first[x] = top++;}int test_cross(int i,int j,int len,int or1,int or2){//判断两个正方形是否相交double x1_left = p[i].x - len/2.;double x1_right = p[i].x + len/2.;double x2_left = p[j].x - len/2.;double x2_right = p[j].x + len/2.;int y1_1 = p[i].y;int y1_2 = p[i].y + or1*len;int y2_1 = p[j].y;int y2_2 = p[j].y + or2*len;if((x1_right>x2_left) && (x2_right>x1_left) &&max(y1_1,y1_2) > min(y2_1,y2_2) &&max(y2_1,y2_2) > min(y1_1,y1_2) )return 1;return 0;}void tarjan(int x){int i;dfn[x] = low[x] = ++index;stack[++tops] = x;for(i=first[x];i!=-1;i=e[i].next){if(dfn[e[i].y] == -1){tarjan(e[i].y);low[x] = min(low[x],low[e[i].y]);}else if(!strong[e[i].y])low[x] = min(low[x],dfn[e[i].y]);}if(dfn[x] == low[x]){num++;do{strong[stack[tops]] = num;}while(stack[tops--]!=x);}}int main(){freopen("a.txt","r",stdin);scanf("%d",&T);while(T--){int i,j;lo = 0;high = 10000;//二分答案scanf("%d",&n);for(i = 1;i<=n;i++)scanf("%d %d",&p[i].x,&p[i].y);while(lo <= high){init();//注意初始化的位置mid = (lo+high)>>1;for(i = 1;i<n;i++)//建图for(j = i+1;j<=n;j++){if(test_cross(i,j,mid,-1,-1))add(i,j+n),add(j,i+n);if(test_cross(i,j,mid,-1,1))add(i,j),add(j+n,i+n);if(test_cross(i,j,mid,1,-1))add(i+n,j+n),add(j,i);if(test_cross(i,j,mid,1,1))add(i+n,j),add(j+n,i);}for(i = 1;i<=2*n;i++)//tarjan求强连通分量if(dfn[i] == -1)tarjan(i);for(i = 1;i<=n;i++)if(strong[i] == strong[i+n])//如果有一个点的两种情况在同一个连通分量中(也就是必须同时满足)break;if(i > n){//答案合理res = mid;lo = mid+1;}elsehigh = mid-1;}printf("%d\n",res);}return 0;}


0 0