题解 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]=minegin{cases}dp[i-1][j][0]+dis[C1][C2]\dp[i-1][j][1]+dis[D1][C2] imes k[i-1]+dis[C1][C2] imes (1-k[i-1])end{cases})
2. (k=1),换
若上一次不换,则加上这次成功和不成功的期望。
若上一次换,则
(mathfrak{(1)})上次成功,这次成功
(mathfrak{(2)})}上次成功,这次不成功
(mathfrak{(3)})上次不成功,这次成功
(mathfrak{(4)})上次不成功,这次不成功
(dp[i][j][1]=minegin{cases}dp[i-1][j-1][0]+dis[C1][D2] imes k[i]+dis[C1][C2] imes (1-k[i])\dp[i-1][j-1][1]+mathfrak{(1)}mp[D1][D2] imes k[i-1] imes k[i]+mathfrak{(2)}dis[D1][C2] imes k[i-1] imes (1-k[i])+mathfrak{(3)}dis[C1][D2] imes (1-k[i-1]) imes k[i]+mathfrak{(4)}dis[C1][C2] imes (1-k[i-1]) imes (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;
}