hdoj 3622 Bomb Game 【2-sat + 二分搜索】

来源:互联网 发布:旅游网络市场调查 编辑:程序博客网 时间:2024/06/07 04:35

Bomb Game

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4291    Accepted Submission(s): 1520


Problem Description
Robbie is playing an interesting computer game. The game field is an unbounded 2-dimensional region. There are N rounds in the game. At each round, the computer will give Robbie two places, and Robbie should choose one of them to put a bomb. The explosion area of the bomb is a circle whose center is just the chosen place. Robbie can control the power of the bomb, that is, he can control the radius of each circle. A strange requirement is that there should be no common area for any two circles. The final score is the minimum radius of all the N circles.
Robbie has cracked the game, and he has known all the candidate places of each round before the game starts. Now he wants to know the maximum score he can get with the optimal strategy.
 

Input
The first line of each test case is an integer N (2 <= N <= 100), indicating the number of rounds. Then N lines follow. The i-th line contains four integers x1i, y1i, x2i, y2i, indicating that the coordinates of the two candidate places of the i-th round are (x1i, y1i) and (x2i, y2i). All the coordinates are in the range [-10000, 10000].
 

Output
Output one float number for each test case, indicating the best possible score. The result should be rounded to two decimal places.
 

Sample Input
21 1 1 -1-1 -1 -1 121 1 -1 -11 -1 -1 1
 

Sample Output
1.411.00
 

题意:给你N个炸弹,每个炸弹只能放在两个位置(给出4个坐标 对应两个位置),这些炸弹可以伤害到以它为圆心半径为r的圆域。你可以控制炸弹的威力即圆域半径r,现在要求任意两个炸弹所能伤害的圆域不能重叠,让你求出满足条件的最大半径。

建图:对于每个炸弹 i 若放在第一个位置则有Ai, 放在第二个位置则有!Ai。
那么对于任意炸弹 i 和 j 建边方案有四:

一:i 放在第一个位置 和 j 放在第一个位置不能兼得; 即 Ai 析取 Bj

二:i 放在第一个位置 和 j 放在第二个位置不能兼得; 即 Ai 析取 !Bj

三:i 放在第二个位置 和 j 放在第一个位置不能兼得; 即 !Ai 析取 Bj

四:i 放在第二个位置 和 j 放在第二个位置不能兼得; 即 !Ai 析取 !Bj

二分搜索每次建图并判断是否2-sat有解即可


#include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <queue>#include <stack>#include <vector>#include <algorithm>#define MAXN 200+10#define MAXM 400000+10#define INF 10000000#define eps 1e-5using namespace std;struct rec{double x1, y1, x2, y2;}num[110];//存储每个炸弹可以放置的两个位置 vector<int> G[MAXN];//存储图  int N;//炸弹数目  构成图后图中点数为2*N bool judge(double x1, double y1, double x2, double y2, double r){return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) + eps < 2 * r;//相交 }void getpos(){for(int i = 0; i < N; i++)scanf("%lf%lf%lf%lf", &num[i].x1, &num[i].y1, &num[i].x2, &num[i].y2);}void init(){for(int i = 0; i < 2*N; i++) G[i].clear();//注意2*N个点 }void getMap(double r){for(int i = 0; i < N; i++){for(int j = 0; j < i; j++){if(judge(num[i].x1, num[i].y1, num[j].x1, num[j].y1, r))//i放在第一个位置 和 j放在第一个位置不能兼得 {G[i].push_back(j + N);G[j].push_back(i + N);}if(judge(num[i].x1, num[i].y1, num[j].x2, num[j].y2, r))//i放在第一个位置 和 j放在第二个位置不能兼得{G[i].push_back(j);G[j + N].push_back(i + N);//这里开始建错了 }if(judge(num[i].x2, num[i].y2, num[j].x1, num[j].y1, r))//i放在第二个位置 和 j放在第一个位置不能兼得{G[i + N].push_back(j + N);G[j].push_back(i);}if(judge(num[i].x2, num[i].y2, num[j].x2, num[j].y2, r))//i放在第二个位置 和 j放在第二个位置不能兼得{G[i + N].push_back(j);G[j + N].push_back(i);}}}}int low[MAXN], dfn[MAXN];int dfs_clock;int sccno[MAXN], scc_cnt;stack<int> S;bool Instack[MAXN];void tarjan(int u, int fa){int v;low[u] = dfn[u] = ++dfs_clock;S.push(u);Instack[u] = true;for(int i = 0; i < G[u].size(); i++){v = G[u][i];if(!dfn[v]){tarjan(v, u);low[u] = min(low[u], low[v]);}else if(Instack[v])low[u] = min(low[u], dfn[v]);}if(low[u] == dfn[u]){scc_cnt++;for(;;){v = S.top(); S.pop();Instack[v] = false;sccno[v] = scc_cnt;if(v == u) break; }}}void find_cut(int l, int r){memset(low, 0, sizeof(low));memset(dfn, 0, sizeof(dfn));memset(sccno, 0, sizeof(sccno));memset(Instack, false, sizeof(Instack));dfs_clock = scc_cnt = 0;for(int i = l; i <= r; i++)if(!dfn[i]) tarjan(i, -1);} bool two_sat(double r){init();//初始化 getMap(r);//建图 find_cut(0, 2*N-1);//找SCC for(int i = 0; i < N; i++)//判断是否有矛盾 {if(sccno[i] == sccno[i+N]) return false;}return true;} void solve()//二分搜索  {double left, right, mid;left = 0, right = 2000000;//最大半径 while(right - left > eps)//终止 {mid = (left + right) / 2;    if(two_sat(mid))//满足left = mid;else//不满足一定是半径过大right = mid; }printf("%.2lf\n", left);}int main(){while(scanf("%d", &N) != EOF){getpos();//得到炸弹可能位置 solve(); }return 0;}



0 0