【推導】【數學指望】【冒泡排序】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;
}
相關文章
相關標籤/搜索