【概率】SRM503 KingdomXCitiesandVillages

题意:

有N座城市,M个乡村,初始状态下乡村与城市之间没有任何边相连,现在需要将每个乡村都与城市相连。连接方式是:
随机选择一个未连接的乡村,将其与最近的已经与城市相连的点连接(即城市或已连接城市的乡村)
代价即为这两个点的直线距离。
求最终代价的期望值。
N,M50 N , M ≤ 50


分析:

对于这类每个点都会参与计算的题目,应该要很快想到主要方式应该为计算贡献。
我们考虑每个乡村的代价:很显然,对于一个乡村 u u ,若存在另一个乡村v使得 dist(u,v) d i s t ( u , v ) 可能会造成贡献,必然满足 dist(u,v)uu d i s t ( u , v ) < 与 u 最 近 的 城 市 的 到 u 的 距 离
再来看连接的方式:每次都是随机连接,所以很显然最终任意一组排列都是等可能的方案。
所以如果一个点对 (u,v) ( u , v ) 的距离被计算,则其必然满足所有到u的距离小于v的点在排列中均在v点之后。
假设要满足有特定的k个点在排列中位于v之后,则概率为:

1n+(nk1)n(n1)+(nk1)(nk2)n(n1)(n2) 1 n + ( n − k − 1 ) n ( n − 1 ) + ( n − k − 1 ) ( n − k − 2 ) n ( n − 1 ) ( n − 2 ) … …

由于本题数据过小,这样臃肿的计算公式也可以跑过,所以我就懒得化简了

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 55
using namespace std;
pair<double,double> c[MAXN],v[MAXN];
double pos[MAXN],t[MAXN],ans;
bool used[MAXN];
int n,m;
double get_pos(int k){
    double res=0;
    for(int i=m-k-1,j=1;i>=0;i--,j++)
        res+=(t[m-k-1]*t[m-j])/(t[m]*t[i]);
    return res;
}
void prepare(){
    t[0]=1;
    for(int i=1;i<=m;i++)
        t[i]=t[i-1]*double(i);
    for(int i=1;i<=m;i++)
        pos[i]=get_pos(double(i));
}
long long dist2(pair<double,double> a,pair<double,double> b){
    long long x2=(long long)(a.first);
    long long y2=(long long)(a.second);
    long long x3=(long long)(b.first);
    long long y3=(long long)(b.second);
    return (x3-x2)*(x3-x2)+(y3-y2)*(y3-y2);
}
double dist(pair<double,double> a,pair<double,double> b){
    double res1=double(dist2(a,b));
    return sqrt(res1);
}
class KingdomXCitiesandVillages{
public:
    double determineLength(vector<int> r1,vector<int> r2,vector<int> r3,vector<int> r4){
        //SF("%d%d",&n,&m);
        n=r1.size(),m=r3.size();
        prepare();
        for(int i=0;i<n;i++){
            //SF("%lf",&c[i].first);
            c[i].first=double(r1[i]);
        }
        for(int i=0;i<n;i++){
            //SF("%lf",&c[i].second);
            c[i].second=double(r2[i]);
        }
        for(int i=0;i<m;i++){
            //SF("%lf",&v[i].first);
            v[i].first=double(r3[i]);
        }
        for(int i=0;i<m;i++){
            //SF("%lf",&v[i].second);
            v[i].second=double(r4[i]);
        }
        for(int i=0;i<m;i++){
            int minid,minid1,cnt=0;
            double p=1;
            memset(used,0,sizeof used);
            used[i]=1;
            minid1=-1;
            for(int j=0;j<n;j++)
                if(minid1==-1||dist2(v[i],c[j])<dist2(v[i],c[minid1]))
                    minid1=j;
            while(1){
                minid=-1;
                for(int j=0;j<m;j++)
                    if(used[j]==0&&(minid==-1||dist2(v[i],v[j])<dist2(v[i],v[minid])))
                        minid=j;
                if(minid==-1||dist2(v[i],v[minid])>dist2(v[i],c[minid1])){
                    ans+=dist(v[i],c[minid1])*p;
                    //PF("[%d %lf %lf]\n",i,p,dist(v[i],c[minid1]));
                    break;
                }
                double p1=p*pos[cnt+1];
                //PF("[%d %lf %lf]\n",i,p1,dist(v[i],v[minid]));
                ans+=dist(v[i],v[minid])*p1;
                p-=p1;
                cnt++;
                used[minid]=1;
            }
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值