【NOIP2016换教室】概率DP

本题由于算法比较显然,直接写出算法 Luogu 1850 本题概率DP, 状态 f[i][j][1/0]前i门课选择了j门要处理换,第i门决定要换的到达状态期望距离 初始化:f[1][1][1]=f[1][0][0]=0,别的f设inf ,对图上的所有两点进行floyd 由于我们知道对于一个状态是从哪个地方转化过来增加距离只与i和i-1的概率有关(失败或成功要从哪个结点转向另外哪一个点有距离*概率的和为其转化状态的期望) 然后对于f[i][j][0]有 min { f[i-1][j][0] + dis(i-1 0 到 i 0) f[i-1][j][1] + dis(i-1 0 到 i 0)*(1-k[i-1]) + dis(i-1 1 到 i 0)*(k[i-1]) } 这里的i-1 0 和 i 0 就是 c[0]和 d[0] ,即从哪个变量的成功或失败后的位置,失败为 0 ,成功为 1 然后对于f[i][j][1] min { f[i-1][j-1][0] + dis(i-1 0到 i 0)*(1-k[i]) + dis(i-1 0 到 i 1)*k[i] f[i-1][j-1][1] + dis(i-1 0 到 i 0)*(1-k[i-1])*(1-k[i]) + dis(i-1 0 到 i 1)*(1-k[i-1])*k[i]+ dis(i-1 1 到 i 0)*k[i-1]*(1-k[i]) + dis(i-1 1 到 i 1)*k[i-1]*k[i] } 最后答案在f[n][1->m][0\1]中找就可以了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;
int n,m,v,e;
int dis[305][305];
double f[2005][2005][2];
int c[2005],d[2005];
double k[2005];

int main()
{
	scanf("%d%d%d%d",&n,&m,&v,&e);
	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
	for(int i=1;i<=n;i++) scanf("%d",&d[i]);
	for(int i=1;i<=n;i++) scanf("%lf",&k[i]);
	for(int i=1;i<=v;i++)
	{
		for(int j=1;j<=v;j++) 
		{
			dis[i][j]=0x3f3f3f3f;
		}
		dis[i][i]=0;
	}
	for(int i=1;i<=e;i++)
	{
		int a,b,w;
		scanf("%d%d%d",&a,&b,&w);
		if(w<dis[a][b])
		{
			dis[a][b]=dis[b][a]=w;
		}
	}
	for(int o=1;o<=v;o++)
	{
		for(int i=1;i<=v;i++)
		{
			for(int j=1;j<=v;j++)
			{
				dis[i][j] = min(dis[i][j],dis[i][o]+dis[o][j]);
			}
		}
	}
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=m;j++) f[i][j][0]=f[i][j][1]=1e9;
	}
	f[1][1][1]=f[1][0][0]=0;
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
		{
			int xx0=c[i-1]; int xx1=d[i-1]; int yy0 = c[i]; int yy1 = d[i]; 
			double kk0 = k[i-1]; double kk1 = k[i];
			f[i][j][0]=min(f[i-1][j][0]+dis[xx0][yy0],f[i-1][j][1]+dis[xx1][yy0]*kk0+dis[xx0][yy0]*(1.0-kk0));
			if(j>0) f[i][j][1]=min( f[i-1][j-1][0] + dis[xx0][yy0]*(1-kk1) + dis[xx0][yy1]*kk1,f[i-1][j-1][1] + dis[xx0][yy0]*(1-kk0)*(1-kk1) + dis[xx0][yy1]*(1-kk0)*kk1 + dis[xx1][yy0]*kk0*(1-kk1) + dis[xx1][yy1]*kk0*kk1 );
		}
	}
	double ans = 1e9;
	for(int i=0;i<=m;i++)
	{
		ans = min(ans,f[n][i][0]);
		ans = min(ans,f[n][i][1]);
	}
	printf("%.2lf",ans);
}
 
posted @ 2018-08-01 18:17  Newuser233  阅读(4)  评论(0)    收藏  举报