[NOIP2016] 换教室

题目分析

此题比第二题简单。。。考场上打了2个Dfs骗了60分 2333333

接下来讲正解

因为要使用多源的最短路径,使用Floyd初始化

数学期望的概念可以参考一下度娘:数学期望

根据数学期望的性质,可以将其线性向后递推,故使用动规

设f[i][j][0..1]表示到第i节课,用了j次换课机会,第i节课是否选择换课

方程如下:

f[i][j][0]=f[i-1][j][1]+a[i-1].probability*floyd.map[a[i-1].change][a[i].original]+(1-a[i-1].probability)*floyd.map[a[i-1].original][a[i].original];//前面一节课选择换教室,这节课不换

f[i][j][0]=fmin(f[i][j][0],f[i-1][j][0]+floyd.map[a[i-1].original][a[i].original]);//前面一节课没有换课,这节课也不选择换 

f[i][j][1]=f[i-1][j-1][0]+a[i].probability*floyd.map[a[i-1].original][a[i].change]+(1-a[i].probability)*floyd.map[a[i-1].original][a[i].original];//前面一节课没有选择换教室,这节课选择换教室

f[i][j][1]=fmin(f[i][j][1],f[i-1][j-1][1]+a[i-1].probability*(a[i].probability*floyd.map[a[i-1].change][a[i].change]+(1-a[i].probability)*floyd.map[a[i-1].change][a[i].original])+(1-a[i-1].probability)*(a[i].probability*floyd.map[a[i-1].original][a[i].change]+(1-a[i].probability)*floyd.map[a[i-1].original][a[i].original]));//前节课选择换教室,这节课也选择换教室

源代码

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
	int num=0,bj=1;
	char x=getchar();
	while(x<'0'||x>'9') {
		if(x=='-')bj=-1;
		x=getchar();
	}
	while(x>='0'&&x<='9') {
		num=num*10+x-'0';
		x=getchar();
	}
	return num*bj;
}
const int maxn=505;
struct Floyd {
	int n;
	int map[maxn][maxn];
	void init(int n) {
		this->n=n;
		for(int i=1; i<=n; i++)
			for(int j=1; j<=n; j++)
				if(i==j)map[i][j]=0;
				else map[i][j]=0x7fffffff/2;
	}
	void AddEdge(int from,int to,int dist) {
		map[from][to]=min(map[from][to],dist);
	}
	void main() {
		for(int k=1; k<=n; k++)
			for(int i=1; i<=n; i++)
				for(int j=1; j<=n; j++)
					map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
	}
} ; 
struct Plan {
	int original,change;
	double probability;
} a[2005];
Floyd floyd;
int Class,Apply,n,m;
double f[2005][2005][2],ans=1e10; 
//设f[i][j][0..1]表示到第i节课,用了j次换课机会,第i节课是否选择换课 
int main() {
	ios::sync_with_stdio(false);
	cin>>Class>>Apply>>n>>m;
	floyd.init(n);
	for(int i=1; i<=Class; i++)cin>>a[i].original;
	for(int i=1; i<=Class; i++)cin>>a[i].change;
	for(int i=1; i<=Class; i++)cin>>a[i].probability;
	for(int i=1; i<=m; i++) {
		int x,y,v;
		cin>>x>>y>>v;
		floyd.AddEdge(x,y,v);
		floyd.AddEdge(y,x,v);
	}
	floyd.main();
    for(int i=1; i<=Class; i++)
        for(int j=0; j<=Apply; j++)
			f[i][j][0]=f[i][j][1]=1e10;
    f[1][0][0]=f[1][1][1]=0;
    for(int i=2; i<=Class; i++)
        for(int j=0; j<=Apply; j++) {
        	f[i][j][0]=f[i-1][j][1]+a[i-1].probability*floyd.map[a[i-1].change][a[i].original]+(1-a[i-1].probability)*floyd.map[a[i-1].original][a[i].original]; //前面一节课选择换教室,这节课不换 
            f[i][j][0]=fmin(f[i][j][0],f[i-1][j][0]+floyd.map[a[i-1].original][a[i].original]); //前面一节课没有换课,这节课也不选择换 
            if(j) {
            	f[i][j][1]=f[i-1][j-1][0]+a[i].probability*floyd.map[a[i-1].original][a[i].change]+(1-a[i].probability)*floyd.map[a[i-1].original][a[i].original]; //前面一节课没有选择换教室,这节课选择换教室
            	f[i][j][1]=fmin(f[i][j][1],f[i-1][j-1][1]+a[i-1].probability*(a[i].probability*floyd.map[a[i-1].change][a[i].change]+(1-a[i].probability)*floyd.map[a[i-1].change][a[i].original])+(1-a[i-1].probability)*(a[i].probability*floyd.map[a[i-1].original][a[i].change]+(1-a[i].probability)*floyd.map[a[i-1].original][a[i].original])); //前节课选择换教室,这节课也选择换教室 
			}
        }
	for(int i=0; i<=Apply; i++)ans=fmin(ans,min(f[Class][i][0],f[Class][i][1]));
    printf("%0.2lf\n",ans);
	return 0;
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值