题解 P1850 [NOIP2016 提高组] 换教室

题解 P1850 [NOIP2016 提高组] 换教室

一.设置状态

\(dp[i][j][k]\)表示走完前\(i\)个教室,换了\(j\)次,\(k=1\)表示上一次换教室了,\(k=0\)表示上一次没有换教室.

二.状态转移

\(C1=c[i-1],D1=d[i-1],C2=c[i],D2=d[i]\)

考虑下列两种情况:

1. \(k=0\),不换

若上一次不换,则只能从C1转移到C2;

若上一次换了,则加上成功的期望和不成功的期望。

\(dp[i][j][0]=\min\begin{cases}dp[i-1][j][0]+dis[C1][C2]\\dp[i-1][j][1]+dis[D1][C2]\times k[i-1]+dis[C1][C2]\times (1-k[i-1])\end{cases}\)

2. \(k=1\),换

若上一次不换,则加上这次成功和不成功的期望。

若上一次换,则

\(\mathfrak{(1)}\)上次成功,这次成功

\(\mathfrak{(2)}\)}上次成功,这次不成功

\(\mathfrak{(3)}\)上次不成功,这次成功

\(\mathfrak{(4)}\)上次不成功,这次不成功

\(dp[i][j][1]=\min\begin{cases}dp[i-1][j-1][0]+dis[C1][D2]\times k[i]+dis[C1][C2]\times (1-k[i])\\dp[i-1][j-1][1]+\mathfrak{(1)}mp[D1][D2]\times k[i-1]\times k[i]+\mathfrak{(2)}dis[D1][C2]\times k[i-1]\times (1-k[i])+\mathfrak{(3)}dis[C1][D2]\times (1-k[i-1])\times k[i]+\mathfrak{(4)}dis[C1][C2]\times (1-k[i-1])\times (1-k[i])\end{cases}\)

三.最短路处理

简单的弗洛伊德Floyd三层循环

\(Cade\)

#include<bits/stdc++.h>
using namespace std;

const int N=2e3+7,M=3e2+7,INF=0x3f3f3f3f;
int n,m,v,e;
int c[N],d[N],dis[M][M];
double k[N],dp[N][N][2];

inline void read(int &x)
{
	char ch=getchar();x=0;
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}

inline void Read()
{
	read(n),read(m),read(v),read(e);
	for(int i=1;i<=n;i++) read(c[i]);
	for(int i=1;i<=n;i++) read(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<i;j++)
			dis[i][j]=dis[j][i]=INF;
	for(int i=1,x,y,z;i<=e;i++)
	{
		read(x),read(y),read(z);
		dis[y][x]=dis[x][y]=min(dis[x][y],z);
	}
}

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

inline void Solve()
{
	for(int i=1;i<=n;i++)
		for(int j=0;j<=m;j++)
			dp[i][j][0]=dp[i][j][1]=INF;
	dp[1][0][0]=dp[1][1][1]=0;
	for(int i=2;i<=n;i++)
		for(int j=0;j<=m;j++)
		{
			dp[i][j][0]=min(dp[i-1][j][0]+dis[c[i-1]][c[i]],dp[i-1][j][1]+dis[c[i-1]][c[i]]*(1-k[i-1])+dis[d[i-1]][c[i]]*k[i-1]);
			if(j!=0)
				dp[i][j][1]=min(dp[i-1][j-1][0]+dis[c[i-1]][d[i]]*k[i]+dis[c[i-1]][c[i]]*(1-k[i]),dp[i-1][j-1][1]+dis[d[i-1]][d[i]]*k[i-1]*k[i]+dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dis[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i]));
		}
	double ans=INF;
	for(int i=0;i<=m;i++)
		for(int j=0;j<=1;j++)
			ans=min(ans,dp[n][i][j]);
	printf("%.2lf",ans);
}

int main()
{
	Read();
	Floyd();
	Solve();
	return 0;
}
posted @ 2021-03-01 21:16  Sure042  阅读(124)  评论(0编辑  收藏  举报