</pre><pre name="code" class="cpp">/*
二分+2-sat
题意:判断以一个点为边中心的上矩形或下矩形是否存在一组使得没有相交的矩形
和hdu 3622 差不多,注意判断矩形相交的方程
i+n为i点的上矩阵,i为i点的下矩阵,j+n为j点的上矩阵,j为j点的下矩阵
关于二分时用left<=right这种形式,用left<right这种形式有毒
*/
#include<stdio.h>
#include<string.h>
#include<math.h>
#define eps 1e-10
#define N 410
struct node {
int u,v,next;
}bian[N*N];
int head[N],dfn[N],low[N],stac[N],yong,index,top,vis[N],ans,belong[N];
void init() {
memset(head,-1,sizeof(head));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
memset(stac,0,sizeof(stac));yong=0;index=0;top=0;;memset(vis,0,sizeof(vis));ans=0;
memset(belong,0,sizeof(belong));
}
void addedge(int u,int v) {
bian[yong].u=u;
bian[yong].v=v;
bian[yong].next=head[u];
head[u]=yong++;
}
int Min(int v,int vv) {
return v>vv?vv:v;
}
void tarjan(int u) {
dfn[u]=low[u]=++index;
stac[++top]=u;
vis[u]=1;
int i;
for(i=head[u];i!=-1;i=bian[i].next) {
int v=bian[i].v;
if(!dfn[v]) {
tarjan(v);
low[u]=Min(low[u],low[v]);
}
else
if(vis[v])
low[u]=Min(low[u],dfn[v]);
}
if(dfn[u]==low[u]) {
ans++;
int t;
do {
t=stac[top--];
belong[t]=ans;
vis[t]=0;
}while(t!=u);
}
}
struct nodee{
int u,v;
}f[N];
int n;
int judgem(nodee a,nodee b,int k,int r) {
double ax,ay,bx,by;
if(k==1||k==2) {
ay=a.v+1.0*r/2;
ax=a.u;
}
if(k==1||k==3) {
by=b.v+1.0*r/2;
bx=b.u;
}
if(k==3||k==4) {
ay=a.v-1.0*r/2;
ax=a.u;
}
if(k==2||k==4) {
by=b.v-1.0*r/2;
bx=b.u;
}
if(fabs(ax-bx)>=1.0*r-eps||fabs(ay-by)>=1.0*r-eps)//判断是否相交的算法
return 0;
return 1;
}
int judge(int r) {
int i,j;
init();
for(i=0;i<n;i++)
for(j=i+1;j<n;j++) {
if(judgem(f[i],f[j],1,r)) {//1的时候判断的是i+n和j+n是否矛盾
addedge(i+n,j);
addedge(j+n,i);
}
if(judgem(f[i],f[j],2,r)) {//2的时候判断的是i+n和j是否矛盾
addedge(i+n,j+n);
addedge(j,i);
}
if(judgem(f[i],f[j],3,r)) {//3的时候判断的是i和j+n是否矛盾
addedge(i,j);
addedge(j+n,i+n);
}
if(judgem(f[i],f[j],4,r)){//4的时候判断的是i和j是否矛盾
addedge(i,j+n);
addedge(j,i+n);
}
}
for(i=0;i<2*n;i++)
if(!dfn[i])
tarjan(i);
for(i=0;i<n;i++)
if(belong[i]==belong[i+n])break;
if(i==n)return 1;
return 0;
}
int main() {
int i;
int left,right,mid,ans;
int t;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&f[i].u,&f[i].v);
right=2*10000*2;left=0;
while(left<=right) {//下次就用这个<=这种形式
mid=(left+right)/2;
if(judge(mid))
left=mid+1;
else
right=mid-1;
}
printf("%d\n",right);//最后输出right
}
return 0;}
poj 2296 二分+2-sat
最新推荐文章于 2019-01-08 01:56:48 发布