洛谷传送门
Atcoder传送门
题目描述
在一个二维平面上有 N N N个城市, 第 i i i个城市的坐标是 ( x i , y i ) (x_i,y_i) (xi,yi), 一开始拥有的水量是 a i a_i ai。
现在你可以从一个城市向另一个城市运送任意数量的水, 但水在运输过程中会有损耗, 具体而言如果从 x x x城市运 l l l水到 y y y城市,最终 y y y城市得到的水量是 m a x ( 0 , l − d i s ( x , y ) ) max(0,l-dis(x,y)) max(0,l−dis(x,y)), 其中 d i s ( x , y ) dis(x,y) dis(x,y)指 x x x和 y y y城市间的欧几里得距离。 你可以多次进行这个操作。
你要使最终水量最少的城市水量尽量多, 求这个值。
输入输出格式
输入格式
第一行一个正整数
N
N
N。
以下
N
N
N行, 每行三个整数
x
i
,
y
i
,
a
i
x_i,y_i,a_i
xi,yi,ai, 含义如上。
输出格式
一行一个实数 a n s ans ans表示最终水量最少的城市水量最多有多少。
输入输出样例
输入样例#1:
3
0 0 10
2 0 5
0 5 8
输出样例#1:
6.500000000000
输入样例#2:
15
335279264 849598327 822889311
446755913 526239859 548830120
181424399 715477619 342858071
625711486 448565595 480845266
647639160 467825612 449656269
160714711 336869678 545923679
61020590 573085537 816372580
626006012 389312924 135599877
547865075 511429216 605997004
561330066 539239436 921749002
650693494 63219754 786119025
849028504 632532642 655702582
285323416 611583586 211428413
990607689 590857173 393671555
560686330 679513171 501983447
输出样例#2:
434666178.237122833729
解题分析
很显然我们选取任意一个子图出来, 能够取到的最大答案要么是这个子图的子图合并起来的最小值, 要么是这个子图的所有点的权值之和减去最小生成树上所有边的长度(如果出现运到某个城市的水是负数也不碍事, 肯定这样是不优的, 我们讨论子集的时候已经考虑到了)。
所以枚举所有子图做最小生成树, 然后枚举子集大力 D P DP DP就好了。
总复杂度 O ( 2 n n 2 l o g ( n ) + 3 n ) O(2^nn^2log(n)+3^n) O(2nn2log(n)+3n)。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <vector>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define db long double
#define ll long long
#define MX 16
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int n, all, cnt;
int bel[MX];
std::vector <int> st;
struct INFO {int x, y, val;} dat[MX];
struct Edge {int from, to; db len;} edge[MX * MX];
IN bool operator < (const Edge &x, const Edge &y)
{return x.len < y.len;}
db res[1 << MX];
IN ll sqr(R int x) {return 1ll * x * x;}
IN db calc(R int x, R int y)
{return sqrtl(sqr(dat[x].x - dat[y].x) + sqr(dat[x].y - dat[y].y));}
int find(R int now) {return bel[now] == now ? now : bel[now] = find(bel[now]);}
IN db MST(R int stat)
{
st.clear(); cnt = 0;
db ret = 0;
for (R int i = 0; i < n; ++i)
{
bel[i] = i;
if ((1 << i) & stat) st.push_back(i), ret += dat[i].val;
}
int tot = st.size(), foo, bar, cot = 0;
for (R int i = 0; i < tot; ++i)
for (R int j = i + 1; j < tot; ++j)
edge[++cnt] = {st[i], st[j], calc(st[i], st[j])};
std::sort(edge + 1, edge + 1 + cnt);
for (R int i = 1; i <= cnt; ++i)
{
foo = find(edge[i].from), bar = find(edge[i].to);
if (foo == bar) continue;
++cot;
bel[foo] = bar;
ret -= edge[i].len;
if (cot == tot - 1) break;
}
return ret / tot;
}
int main(void)
{
in(n); all = (1 << n) - 1;
for (R int i = 0; i < n; ++i)
in(dat[i].x), in(dat[i].y), in(dat[i].val);
for (R int i = 1; i <= all; ++i)
{
res[i] = MST(i);
for (R int s = (i - 1) & i; s; s = (s - 1) & i)
res[i] = std::max(res[i], std::min(res[s], res[i ^ s]));
}
printf("%.10Lf", res[all]);
}

本文探讨了一个涉及多个城市的水资源分配问题,目标是最小化各城市间水资源的差异。通过构建子图,利用最小生成树算法,并结合动态规划,提出了一个复杂度为O(2^n*n^2*log(n)+3^n)的解决方案。

被折叠的 条评论
为什么被折叠?



