KingdomXCitiesandVillages
Task:给定n个城市和m个村庄的坐标。要求将每一个村庄都连接到城市。
你每一次选定一个未连接的村庄,寻找这个村庄到其他一个已经连接到城市的村庄或者是一个城市的最短距离并连接,当然,如果有多个相等的最短距离,你选定其中的每一条道路的概率是均等的,求最后将村庄全部连接到城市的道路长度的期望值。(
n,m<=50
)
Solution:
此题Div2版本很水,就是求以最小生成树的长度。
首先,如果我们直接按题目意思模拟的话,需要确定一个村庄的处理顺序,复杂度为
O(n!)
。显然是会严重超时的,所以我们要对答案做一些变化。
答案所求的期望值=每个村庄连出的边的期望长度之和=每个村庄连出的每条边*该边的出现概率之和
然后我们就可以对于每个村庄来考虑答案了,将这个村庄到其他点的边连起来,按从小到大排序,依次遍历计算出现的概率。
那么我们就只需要求出一条边出现的概率就可以解决问题了。
先来考虑:如果出现了一个连到城市的边,那么后面的边就不用考虑了,因为要求每次都连最短的边,而城市的边与村庄的排列顺序无关(一直都存在),因此后面的边是无法被选到的。
然后,我们如果要选中第i小的边,则
[1..i−1]
之间的边连到的村庄一定在当前村庄的后面处理。即这些村庄尚未与城市相连,才能轮到第
i
小的边。
于是,这就变成了一个排列的问题:
总排列数是
同样的,如果是遇到了城市,概率即为
1cnt+1
。
于是我们就解决了这个问题,复杂度
O(n2)
。
struct Node{
double x;
bool f;
bool operator <(const Node &a)const{
return x<a.x;
}
};
class KingdomXCitiesandVillages {
public:
double dist(int x1,int y1,int x2,int y2){
return sqrt(1LL*(x1-x2)*(x1-x2)+1LL*(y1-y2)*(y1-y2));
}
double determineLength(vector <int> cityX, vector <int> cityY, vector <int> villageX, vector <int> villageY) {
vector<Node>P;
double ans=0;
int n=cityX.size(),m=villageX.size();
for(int i=0;i<m;i++){
P.clear();
for(int j=0;j<m;j++)
if(j!=i)P.push_back((Node){dist(villageX[i],villageY[i],villageX[j],villageY[j]),false});
for(int j=0;j<n;j++)
P.push_back((Node){dist(villageX[i],villageY[i],cityX[j],cityY[j]),true});
sort(P.begin(),P.end());
int cnt=0;
for(int j=0;j<P.size();j++){
if(P[j].f){
ans+=1.0/(cnt+1)*P[j].x;
break;
}else{
cnt++;
ans+=1.0/(cnt*(cnt+1))*P[j].x;
}
}
}
return ans;
}
};