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

本文深入探讨了游戏开发领域的核心技术,包括游戏引擎、图形渲染、音视频处理等关键环节,为开发者提供全面的技术指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
2 1 1 1 -1 -1 -1 -1 1 2 1 1 -1 -1 1 -1 -1 1
 

Sample Output
1.41 1.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-5
using 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值