1. 程式人生 > 實用技巧 >換教室 P1850 (NOIP 2016)

換教室 P1850 (NOIP 2016)

P1850

首先,我們從一節課的教室到另一節課的教室的距離顯然需要儘可能小,所以可以預先跑一遍 Floyed ,把距離處理出來

其次,對於這道 DP ,我們設

\(f[i][j][0/1]\) 為當前已經處理到第 \(i\) 節課,算上本堂課一共用了 \(j\) 次換教室的機會所產生的最小期望和, 其中 \(0/1\) 表示這一節課是換教室,還是不換教室

那麼預處理的時候,顯然,我們需要將 \(f[1][1][1]\) 以及 \(f[1][0][0]\) 均賦值為 \(0\) ,因為第一節課不管換不換教室,到教室的距離總是為 \(0\)


接下來,我們考慮這些狀態之間怎麼轉移

先看程式碼:

	for(int i=2;i<=n;i++)
	{
		double len1=dis[t1[i-1]][t1[i]];//上一節和這一節都不換教室
		double len2=dis[t1[i-1]][t2[i]];//上一節不換教室,這一節換教室
		double len3=dis[t2[i-1]][t1[i]];//上一節換教室,這一節不換教室
		double len4=dis[t2[i-1]][t2[i]];//上一節和這一節都換教室
		
		for(int j=0;j<=min(m,i);j++)
		{
			f[i][j][0]=min(f[i-1][j][0]+len1,f[i-1][j][1]+len3*p[i-1]+len1*(1-p[i-1]));
			if(j!=0) f[i][j][1]=min(f[i-1][j-1][0]+len2*p[i]+len1*(1-p[i]),f[i-1][j-1][1]+len1*(1-p[i-1])*(1-p[i])+len2*(1-p[i-1])*p[i]+len3*p[i-1]*(1-p[i])+len4*p[i-1]*p[i]);
		}
	}

\(len_i\) 表示教室與教室之間的距離 )

對於第一個 \(f[i][j][0]\) 的轉移方程中,由期望公式可以得到 \(len3*p[i-1]+len1*(1-p[i-1])\) ,其中 \(1-p[i-1]\) 為不會發生的概率

對於第二個 \(f[i][j][1]\) 的轉移方程中,min 函式左側的式子可以參考上面 \(f[i][j][0]\) 的式子,min 函式右側的式子即為在上一次與這一次都提出換教室申請時所有可能出現的情況的列舉討論


完整程式碼:

#include<iostream>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;

const ll maxn=2e3+10;

int n,m,v,e;
int t1[maxn],t2[maxn],head[maxn],tot;
double dis[maxn][maxn];
double p[maxn];
double f[maxn][maxn][2];

inline double _min(double a,double b)
{
	return a < b ? a : b;
}

int main(void)
{
	scanf("%d%d%d%d",&n,&m,&v,&e);
	
	for(int i=1;i<=v;i++)
	{
		for(int j=1;j<i;j++)
		{
			dis[i][j]=dis[j][i]=999999999;
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
		{
			f[i][j][0]=f[i][j][1]=999999999;
		}
	}
	
	for(int i=1;i<=n;i++) scanf("%d",&t1[i]);
	for(int i=1;i<=n;i++) scanf("%d",&t2[i]);
	for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
	for(int i=1;i<=e;i++)
	{
		int u,v;
		double w;
		scanf("%d%d%lf",&u,&v,&w);
		dis[u][v]=dis[v][u]=min(dis[u][v],w);
	}
	
	for(int k=1;k<=v;k++)
	{
		for(int i=1;i<=v;i++)
		{
			for(int j=1;j<i;j++)
			{
				dis[i][j]=dis[j][i]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
	
	f[1][1][1]=f[1][0][0]=0;
	
	for(int i=2;i<=n;i++)
	{
		double len1=dis[t1[i-1]][t1[i]];
		double len2=dis[t1[i-1]][t2[i]];
		double len3=dis[t2[i-1]][t1[i]];
		double len4=dis[t2[i-1]][t2[i]];
		
		for(int j=0;j<=min(m,i);j++)
		{
			f[i][j][0]=min(f[i-1][j][0]+len1,f[i-1][j][1]+len3*p[i-1]+len1*(1-p[i-1]));
			if(j!=0) f[i][j][1]=min(f[i-1][j-1][0]+len2*p[i]+len1*(1-p[i]),f[i-1][j-1][1]+len1*(1-p[i-1])*(1-p[i])+len2*(1-p[i-1])*p[i]+len3*p[i-1]*(1-p[i])+len4*p[i-1]*p[i]);
		}
	}
	
	double ans=999999999;
	
	for(int i=0;i<=m;i++)
	{
		ans=min(f[n][i][0],min(f[n][i][1],ans));
	}
	
	printf("%.2lf\n",ans);
	
	return 0;
}