HDU 3622 Bomb Game / 2-SAT

刚刚学 看到很多网上和书上有直接逐点判断的dfs暴力算法 加上今天事情特别多 看了半天

也可以用tarjan判断 这个有空在学

题意不用说了吧 就是求一个半径 n个炸弹吧 每个可以选择2个点之中的一个放 一定要选一个 比你多也不能少 以这n个点为圆心的圆不能相交

然后主要是每次二分建图

假设有(u1,u2) (v1, v2)一对 并且当前二分的半径是mid 如果 u1 和 v1的距离小于mid 那么建立u1->v2  和v1->u2 两条边

接下来就是算法了

我第一个是书上的 直接dfs的

#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 110;
struct Point
{
	int x;
	int y;
}T[maxn][2];
int n;
vector <int> G[maxn*2];
int mark[maxn*2];
int S[maxn*2], c;
bool dfs(int x)
{
	if(mark[x^1])
		return false;
	if(mark[x])
		return true;
	mark[x] = true;
	S[c++] = x;
	for(int i = 0; i < G[x].size(); i++)
		if(!dfs(G[x][i]))
			return false;
	return true;
}

bool solve()
{
	for(int i = 0; i < n*2; i += 2)
	{
		if(!mark[i] && !mark[i+1])
		{
			c = 0;
			if(!dfs(i))
			{
				while(c > 0)
					mark[S[--c]] = false;
				if(!dfs(i+1))
					return false;			
			}
		}
	}
	return true;
}

double dis(Point p1, Point p2)
{
	return sqrt((double)(p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
bool ok(double mid)
{
	for(int i = 0; i < n*2; i++)
		G[i].clear();
	memset(mark, 0, sizeof(mark));
	for(int i = 0; i < n; i++)
	{
		for(int a = 0; a < 2; a++)
		{
			for(int j = i+1; j < n; j++)
			{
				for(int b = 0; b < 2; b++)
				{
				//	printf("%lf\n", dis(T[i][a], T[j][b]));
					if(dis(T[i][a], T[j][b]) < 2 * mid)
					{
						G[2*i+a].push_back(2*j+b^1);
						G[2*j+b].push_back(2*i+a^1);
					//	printf("1 %lf\n", mid);
					}
				}
			}
		}
	}
	return solve();
}
int main()
{
	while(scanf("%d", &n) != EOF)
	{
		double l = 0, r = 100000; 
		for(int i = 0; i < n; i++)
			for(int j = 0; j < 2; j++)
				scanf("%d %d",&T[i][j].x, &T[i][j].y);
		double ans = 0;
		while(fabs(l-r) > 1e-4)
		{
			double m = (l + r) / 2;
			if(ok(m))
			{
				ans = m;
				l = m;
			}
			else
				r = m;
			//printf("%lf\n", m);
		}
		printf("%.2f\n", ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值