农村连接城市

题目:
https://ac.nowcoder.com/acm/problem/21315

平面上有 N N N个城市和 M M M个乡村,一开始没有任何的道路
为了改善这个局面,主席决定采取一些策略使得每个乡村都能连接到至少一个城市
当存在一个乡村与任何城市都没有联系时,执行如下操作

  1. 随机挑选一个未联系的乡村 V V\quad V
  2. 选择离 V V V最近(欧几里得距离)的一个已链接城市的乡村或者城市,如果有多个,满足条件的点,随机选择,假设选择的点为 P P P
  3. V V V P P P之间 建设一条道路
    求期望需要修建多长的道路能使得所有的乡村都能直接或者间接的连接到城市

思路:
可以发现,对于每一个挑选的乡村 V V V,进行连边操作后,一定能够使 V V V直接或间接连到城市(即一个乡村只会操作一次)。令 X i X_i Xi为第 i i i个乡村连出去的边的长度的随机变量, X X X为整个图的长度的随机变量,有
E ( X ) = ∑ i = 1 N E ( X i ) E(X)=\sum_{i=1}^{N}E(X_i) E(X)=i=1NE(Xi)
对于每一个乡村来说,要么连乡村要么连城市,令 P ( x , y ) P(x,y) P(x,y)表示从 x x x连向 y y y的概率, c i c_i ci表示城市, v i v_i vi表示乡村,则
E ( X i ) = ∑ j = 1 N P ( v i , v j ) d i s ( v i , v j ) + ∑ j = 1 M P ( v i , c j ) d i s ( v i , c j ) E(X_i)=\sum_{j=1}^{N}P(v_i,v_j)dis(v_i,v_j)+\sum_{j=1}^{M}P(v_i,c_j)dis(v_i,c_j) E(Xi)=j=1NP(vi,vj)dis(vi,vj)+j=1MP(vi,cj)dis(vi,cj)
我们先来考虑连向城市,会发现只需要考虑离 v i v_i vi最近的城市即可,记为 c j c_j cj,假设还有 x x x个乡村比 c j c_j cj离得更近,则操作 1 1 1的顺序必须满足 v i v_i vi排在这 x x x个乡村之前(相对位置),则
P ( v i , c j ) = 1 x + 1 P(v_i,c_j)=\frac{1}{x+1} P(vi,cj)=x+11
同理对于在这 x x x个乡村中是第 y y y近的乡村 v j v_j vj来说,有
P ( v i , v j ) = 1 y ( y + 1 ) P(v_i,v_j)=\frac{1}{y(y+1)} P(vi,vj)=y(y+1)1

貌似不用考虑存在相同的距离

#include <cmath>
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;

const int maxn = 55;
const double eps = 1e-9;

struct point {
	int x, y;
	bool isc;
} c[maxn], v[maxn], t[maxn << 1];

inline double sqr(double x) { return x * x; }
inline double dis(const point& a, const point& b) {
	return sqrt(1.0 * sqr(a.x - b.x) + sqr(a.y - b.y));
}
int i, j;
bool cmp (const point& a, const point& b) {
	return dis(v[i], a) == dis(v[i], b) ? a.isc < b.isc : dis(v[i], a) < dis(v[i], b);
}

int main() {
	int n, m;
	cin >> n >> m;
	for (i = 0; i < n; i++)
		cin >> c[i].x;
	for (i = 0; i < n; i++)
		cin >> c[i].y;
	for (i = 0; i < m; i++)
		cin >> v[i].x;
	for (i = 0; i < m; i++)
		cin >> v[i].y;
	double ans = 0;
	for(i = 0; i < m; i++) {
		int cnt = 0;
		for (j = 0; j < n; j++)
			t[cnt] = c[j], t[cnt++].isc = 1;
		for (j = 0; j < m; j++) if(i != j)
				t[cnt] = v[j], t[cnt++].isc = 0;
		sort(t, t + cnt, cmp);
		for (j = 0; j < cnt; j++) {
			if(t[j].isc == 1) {
				ans += dis(t[j], v[i]) / (j + 1);
				break;
			}
			ans += dis(t[j], v[i]) / (j + 1) / (j + 2);
		}
	}

	cout << fixed << setprecision(10) << ans << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值