[Noip2016]换教室

[Noip2016]换教室

一.前言

​ 阿巴阿巴,好长的题面……题目链接

二.思路

​ 看到数学期望就基本知道是DP了,然后状态也比较好想,属于最基础的那种 (f_{ij}) 表示前 i 个共提交了 j 次申请,但是涉及到申请的概率会交叉的问题,于是再加一维 0/1 表示这次是否尝试

​ 这里多嘴一句,一开始我还以为是总共只能成功 m 次,就把方程设成了 j 次成功……然后后面 0/1 那一维也是不可以设成成功的。(可以自己试试,反正我不行)

​ 然后开始转移,对于当前情况,有(dis 表示教室之间的距离)

[f[i][j][0]= ext{min}(dp[i-1][j][0]+dis[c[i-1]][c[i]],\ dp[i-1][j][1]+(1.0-k[i-1])*dis[c[i-1]][c[i]]+k[i-1]*dis[d[i-1]][c[i]]) ]

就稍微解释……这次没有尝试,则上一次就要尝试 j 次,然后由上次没尝试和尝试了的成功与否转移。同理,

[dp[i][j][1]=min( dp[i-1][j-1][0]+k[i]*dis[c[i-1]][d[i]]+(1.0-k[i])*dis[c[i-1]][c[i]],\ dp[i-1][j-1][1]+ k[i-1]*k[i]*dis[d[i-1]][d[i]]+ (1.0-k[i-1])*k[i]*dis[c[i-1]][d[i]]+\ k[i-1]*(1.0-k[i])*dis[d[i-1]][c[i]]+ (1.0-k[i-1])*(1.0-k[i])*dis[c[i-1]][c[i]] ) ]

感觉有点过于长了……跟上面相同的思想我就不讲了。

​ 最后是关于 dis ,看数据范围,教室数小于300 ,Floyd芜湖起飞~ (鬼知道我白给一个小时打了个什么奇怪算法呢~)

​ 就酱。

三.CODE

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<fstream>
#include<cmath>
#include<cstring>
using namespace std;
#define m_for(i,a,b) for(int i=a;i<=b;++i)
int read(){
	char ch=getchar();
	int res=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())res=res*10+(ch-'0');
	return res*f;
}
const int MAXN=90005;
int n,m,v,e;
int c[MAXN],d[MAXN],dis[305][305];
double p[2005][2005][2],dp[2005][2005][2];
double k[MAXN];
int main(){
	memset(dis,127/3,sizeof(dis));
	n=read();m=read();v=read();e=read();
	m=min(m,n);
	m_for(i,1,n)c[i]=read();
	m_for(i,1,n)d[i]=read();
	m_for(i,1,n)scanf("%lf",&k[i]);
	m_for(i,1,v)dis[i][0]=dis[0][i]=dis[i][i]=0.0;
	for(int i=1,a,b,w;i<=e;++i){
		a=read();b=read();w=read();
		dis[a][b]=dis[b][a]=min(dis[b][a],w);
	}
	m_for(a,1,v)m_for(b,1,v)m_for(w,1,v)
	dis[b][w]=min(dis[b][w],dis[b][a]+dis[a][w]);
	m_for(i,1,n)m_for(j,0,m)dp[i][j][0]=dp[i][j][1]=MAXN*100.0;
	dp[1][1][1]=dp[1][0][0]=0.0;
	m_for(i,2,n){
		dp[i][0][0]=dp[i-1][0][0]+dis[c[i-1]][c[i]];
		for(int j=1;j<=i&&j<=m;++j){
			dp[i][j][1]=min(
			dp[i-1][j-1][0]+k[i]*dis[c[i-1]][d[i]]+(1.0-k[i])*dis[c[i-1]][c[i]],
			dp[i-1][j-1][1]+
			k[i-1]*k[i]*dis[d[i-1]][d[i]]+
			(1.0-k[i-1])*k[i]*dis[c[i-1]][d[i]]+
			k[i-1]*(1.0-k[i])*dis[d[i-1]][c[i]]+
			(1.0-k[i-1])*(1.0-k[i])*dis[c[i-1]][c[i]]
			);
			dp[i][j][0]=min(
			dp[i-1][j][0]+dis[c[i-1]][c[i]],
			dp[i-1][j][1]+(1.0-k[i-1])*dis[c[i-1]][c[i]]+k[i-1]*dis[d[i-1]][c[i]]
			);
		}
	}
	double ans=MAXN*100.0;
	for(int i=0;i<=m;++i){
		ans=min(ans,min(dp[n][i][0],dp[n][i][1]));
	}
	printf("%.2lf",ans);
	return 0;
} 
原文地址:https://www.cnblogs.com/clockwhite/p/13493475.html