【推导】【数学指望】【冒泡排序】Petrozavodsk Winter Training Camp 2018 Day 5: Grand Prix of Korea, Sunday, February

题意:两地之间有n条不相交路径,第i条路径由a[i]座桥组成,每座桥有一个损坏几率,让你肯定一个对全部桥的检测顺序,使得检测所需的总指望次数最小。spa

首先,显然检测的时候,是一条路径一条路径地检测,跳跃地检测没有意义。考虑已经排好的某个路径的顺序,相邻的两条路径j和j+1若是知足:blog

(route[j].A+route[j].B)+(route[j+1].A+route[j+1].B)*(1.0-route[j].c)>
(route[j].A+route[j].B)*(1.0-route[j+1].c)+(route[j+1].A+route[j+1].B)排序

就交换它们的顺序使得答案变得更优。it

用相似冒泡的方法扫n次便可。io

A是routej的所有桥良好的指望检查次数,即全部桥好的几率之积乘以桥的数量。B是routej坏的状况下的指望检测次数,至关于对每座桥损坏几率从大到小排序,而后对每一个桥k,其前面k-1个桥全好,它坏的几率,乘上k,而后对这个值求和。c是全部桥好的几率之积,即这个路径好的几率。class

最后输出答案的时候,对全部路径求个其前面的全部路径都坏的几率*(A+B)之和便可。route

#include<cstdio>
#include<algorithm>
using namespace std;
struct data{
	double A,B,c;
}bridge[1005];
int n,x[1005];
int y[1005];
bool cmp(const int &a,const int &b){
	return a>b;
}
int main(){
	//freopen("c.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&x[i]);
		double nowhao=1.0;
		double huaiall=0;
		for(int j=1;j<=x[i];++j){
			scanf("%d",&y[j]);
		}
		sort(y+1,y+x[i]+1);
		for(int j=1;j<=x[i];++j){
			huaiall+=(double)j*nowhao*(1.0-(double)y[j]/1000.0);
			nowhao*=((double)y[j]/1000.0);
		}
		bridge[i].A=nowhao*(double)x[i];
		bridge[i].B=huaiall;
		bridge[i].c=nowhao;
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<n;++j){
			if((bridge[j].A+bridge[j].B)+(bridge[j+1].A+bridge[j+1].B)*(1.0-bridge[j].c)>
			(bridge[j].A+bridge[j].B)*(1.0-bridge[j+1].c)+(bridge[j+1].A+bridge[j+1].B)){
				swap(bridge[j],bridge[j+1]);
			}
		}
	}
	double ans=0;
	double now=1.0;
	double sum=0;
	for(int i=1;i<=n;++i){
		ans+=now*(bridge[i].A+bridge[i].B);
		now*=(1.0-bridge[i].c);
	}
	printf("%.10f\n",ans);
	return 0;
}
相关文章
相关标签/搜索