poj 2296 二分+2-sat

</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;}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值