题解 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;
}