一名苦逼的OIer,想成为ACMer

Iowa_Battleship

JoyOI1935 导弹防御塔

原题链接

首先可以二分答案,然后考虑检验答案。
我们可以对炮塔进行拆点,即能发射\(x\)颗导弹就拆成\(n\times x\)个点,作为一个集合,另一个集合则是\(m\)个侵入者,然后对于能在剩余时间攻击到侵入者的炮弹和该侵入者连边,然后跑匈牙利或网络流求二分图最大匹配即可(本质是多重匹配,使用拆点法)。

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 55;
const int M = 1e6 + 10;
const int K = 1e5 + 10;
struct dd {
	double x, y;
};
dd a[N], b[N];
int fi[K], di[M], ne[M], mtc[K], l, t_2, n, m;
double dis[N][N], t_1;
bool v[K];
inline int re()
{
	int x = 0;
	char c = getchar();
	bool p = 0;
	for (; c < '0' || c > '9'; c = getchar())
		p |= c == '-';
	for (; c >= '0' && c <= '9'; c = getchar())
		x = x * 10 + c - '0';
	return p ? -x : x;
}
inline void add(int x, int y)
{
	di[++l] = y;
	ne[l] = fi[x];
	fi[x] = l;
}
bool dfs(int x)
{
	int i, y;
	for (i = fi[x]; i; i = ne[i])
		if (!v[y = di[i]])
		{
			v[y] = 1;
			if (!mtc[y] || dfs(mtc[y]))
			{
				mtc[y] = x;
				return true;
			}
		}
	return false;
}
bool judge(double mid)
{
	int i, j, s = 0, k = 0;
	double T = mid;
	memset(fi, 0, sizeof(fi));
	memset(mtc, 0, sizeof(mtc));
	l = 0;
	while (T >= t_1)
	{
		T -= t_1;
		k++;
		for (i = 1; i <= m; i++)
			for (j = 1; j <= n; j++)
				if (dis[j][i] <= T)
					add(i, (k - 1) * n + j);
		T -= t_2;
	}
	for (i = 1; i <= m; i++)
	{
		memset(v, 0, sizeof(v));
		if (dfs(i))
			s++;
	}
	return !(s ^ m);
}
int main()
{
	int i, j, x, y, V;
	double l, r = 3e4, mid;
	n = re();
	m = re();
	l = t_1 = re() * 1.0 / 60;
	t_2 = re();
	V = re();
	for (i = 1; i <= m; i++)
	{
		a[i].x = re();
		a[i].y = re();
	}
	for (i = 1; i <= n; i++)
	{
		x = re();
		y = re();
		for (j = 1; j <= m; j++)
			dis[i][j] = sqrt(1.0 * (x - a[j].x) * (x - a[j].x) + 1.0 * (y - a[j].y) * (y - a[j].y)) / V;
	}
	while (l + 1e-7 < r)
	{
		mid = (l + r) / 2;
		if (judge(mid))
			r = mid;
		else
			l = mid;
	}
	printf("%.6f", r);
	return 0;
}

posted on 2018-09-13 19:44  Iowa_Battleship  阅读(172)  评论(0编辑  收藏  举报

导航