【NOIP2016提高组T3】换教室-Floyd+概率DP

测试地址:换教室

做法:设f[i][j][0/1]表示前i个教室选j个申请,其中第i个不申请或申请(最后一个0或1)的最小期望,发现满足动态规划的无后效性原则,再根据和的期望等于期望的和,得到状态转移方程(太长就不在这写了,直接看代码吧),于是用Floyd预处理出两点之间的最短路即可。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,v,e;
int c[2010],d[2010];
double f[2][2010][2],g[310][310],p[2010],inf=1000000.0*1000000.0,dis;

void floyd()
{
  for(int k=1;k<=v;k++)
    for(int i=1;i<=v;i++)
	  for(int j=1;j<=v;j++)
	    g[i][j]=g[j][i]=min(g[i][k]+g[k][j],g[i][j]);
}

int main()
{
  scanf("%d%d%d%d",&n,&m,&v,&e);
  for(int i=1;i<=v;i++)
    for(int j=1;j<=v;j++)
	{
	  if (i!=j) g[i][j]=inf;
      else g[i][j]=0;
	}
  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",&p[i]);
  for(int i=1,a,b;i<=e;i++)
  {
    scanf("%d%d%lf",&a,&b,&dis);
	g[a][b]=g[b][a]=min(g[a][b],dis);
  }
  
  floyd();
  int now=1,past=0;
  memset(f,0,sizeof(f));
  f[0][0][1]=inf;
  for(int i=2;i<=n;i++)
  {
    for(int j=0;j<=m;j++)
	{
	  f[now][j][0]=f[now][j][1]=inf;
	  f[now][j][0]=min(f[now][j][0],f[past][j][0]+g[c[i-1]][c[i]]);
	  f[now][j][0]=min(f[now][j][0],f[past][j][1]
	  +p[i-1]*g[d[i-1]][c[i]]+(1-p[i-1])*g[c[i-1]][c[i]]);
	  if (j>0&&p[i])
	  {
		f[now][j][1]=min(f[now][j][1],f[past][j-1][0]
		+p[i]*g[c[i-1]][d[i]]+(1-p[i])*g[c[i-1]][c[i]]);
		f[now][j][1]=min(f[now][j][1],f[past][j-1][1]
		+p[i-1]*p[i]*g[d[i-1]][d[i]]+(1-p[i-1])*p[i]*g[c[i-1]][d[i]]
		+p[i-1]*(1-p[i])*g[d[i-1]][c[i]]+(1-p[i-1])*(1-p[i])*g[c[i-1]][c[i]]);
	  }
	}
	swap(now,past);
  }
  
  printf("%.2lf",min(f[past][m][0],f[past][m][1]));
  
  return 0;
}


原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793786.html