HDU 3622 Bomb Game【2-SAT 问题】

HDU 3622 Bomb Game【2-SAT 问题】

分类: 【图论专辑】   594人阅读  评论(0)  收藏  举报

       题目大意:有N对点,给定这N对点的坐标,现在要求找出一个最大的半径R,使得可以从每对点中选择一个点,并且这N个点以自己为圆心,半径为R的圆两两不相交。

       2-SAT问题解法:对于每一对点,我们且称之为“兄弟点”;对于这2*N个点,如果两个点之间“矛盾”,对于本题即两个圆相交,则连一条边。对这个图求强连通分量,然后看是否有某对点属于同一个强连通分量。如果N对点每一对都属于不同的强连通分量,满足。否则不满足。然后二分半径即可。

[cpp]  view plain copy
  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <cmath>  
  4. #define MAXN 210  
  5. #define EPS 1e-3  
  6. using namespace std;  
  7. int n;  
  8. struct Edge{  
  9.     int v,next;  
  10.     Edge(){}  
  11.     Edge(int _v,int _next):v(_v),next(_next){}  
  12. }edge[MAXN*MAXN];  
  13. int head[MAXN], size;  
  14. inline void initial(){  
  15.     memset(head,-1,sizeof(int)*(n+2));  
  16.     size = 0;  
  17. }  
  18. inline void add_edge(int u,int v){  
  19.     edge[size] = Edge(v,head[u]);  
  20.     head[u] = size ++;  
  21. }  
  22.   
  23. int belong[MAXN];   
  24. bool vis[MAXN];  
  25. int depth;                   
  26. int bcnt;                    
  27. int dfn[MAXN], low[MAXN];    
  28.                              
  29. int stack[MAXN], tail ;  
  30. inline void Tarjan(int u){  
  31.     dfn[u] = low[u] = depth ++;  
  32.     vis[u] = 1;  
  33.     stack[++tail] = u;  
  34.     for(int i = head[u];i != -1;i = edge[i].next){  
  35.         int v = edge[i].v;  
  36.         if(dfn[v] == -1){  
  37.             Tarjan(v);  
  38.             if(low[u] > low[v])  
  39.                 low[u] = low[v];  
  40.         }else if(vis[v] && low[u] > dfn[v]){  
  41.                 low[u] = dfn[v];  
  42.         }  
  43.     }  
  44.     if(low[u] == dfn[u]){    
  45.         bcnt ++;  
  46.         int j;  
  47.         do{  
  48.             j = stack[tail--];  
  49.             vis[j] = 0;  
  50.             belong[j] = bcnt;  
  51.         }while(j != u);  
  52.     }  
  53. }  
  54. double x[MAXN], y[MAXN];  
  55. inline double Cal(int i,int j){  
  56.     return (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]);  
  57. }  
  58. inline bool can(){  
  59.     int N = n/2;  
  60.     for(int i = 1;i <= N; ++i)  
  61.         if(belong[i] == belong[i+N]) return false;  
  62.     return true;  
  63. }  
  64. int main()  
  65. {  
  66.     int N;  
  67.     while(scanf("%d",&N) != EOF){  
  68.         n = 2*N;  
  69.         for(int i = 1;i <= N; ++i)  
  70.             scanf("%lf%lf%lf%lf",&x[i],&y[i],&x[i+N],&y[i+N]);  
  71.         double right = 10000.0*10000.0, left = 0.0, mid;  
  72.         while(right - left >= EPS){  
  73.             mid = (right + left)/2.0;  
  74.             initial();  
  75.             for(int i = 1;i < n; ++i)  
  76.                 for(int j = i + 1;j <= n; ++j){  
  77.                     //if(i + N == j) continue;  
  78.                     if(Cal(i,j) < mid){  
  79.                         int u, v;  
  80.                         if(i <= N) u = i + N;  
  81.                         else       u = i - N;  
  82.                         if(j <= N) v = j + N;  
  83.                         else       v = j - N;  
  84.                         add_edge(i,v);  
  85.                         add_edge(j,u);  
  86.                     }  
  87.                 }  
  88.             tail = depth = bcnt = 0;  
  89.             memset(vis,0,sizeof(bool)*(n+2));  
  90.             memset(dfn,-1,sizeof(int)*(n+2));  
  91.             memset(low,0,sizeof(int)*(n+2));  
  92.             for(int i = 1;i <= n; ++i)  
  93.                 if(dfn[i] == -1) Tarjan(i);  
  94.             if(can()) left = mid;  
  95.             else right = mid;  
  96.         }  
  97.         printf("%.2lf/n",sqrt(left)/2.0);  
  98.     }  
  99. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值