[NOIP2016] 换教室

[NOIP2016] 换教室_第1张图片[NOIP2016] 换教室_第2张图片[NOIP2016] 换教室_第3张图片[NOIP2016] 换教室_第4张图片[NOIP2016] 换教室_第5张图片[NOIP2016] 换教室_第6张图片[NOIP2016] 换教室_第7张图片

题目分析

此题比第二题简单。。。考场上打了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
#include
#include
#include
#include
#include
#include
#include
#include
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;
}


你可能感兴趣的:(动规Dp,最短路径,OI,信息学,动规,最短路径)