传送门:http://cogs.pro/cogs/problem/problem.php?pid=2558
教室数很小,路又很多,考虑用floyd.(开始把k打里面了,颜面扫地。。)
因为只能提交m个,所以数组就是三维,f[i][j][0/1].i表示第几节课,j表示到i时选了多少节,第三维表示i是否选
既然提交后不知道能否通过,所以期望要分类讨论(废话)一共四种情况,也就是i选没选,i-1选没选,
r1(原来的),r2(换后的)。
分别写一下吧,
i-1不选,i不选,f[i][j][0]=f[i-1][j][0]+dis[r1[i-1]][r1[i]];
i-1选,i不选, f[i][j][0]=f[i-1][j][1]+luck[i-1]*dis[r2[i-1]][r1[i]];
i-1不选,i 选 , 类似。
i-1,i均选 讨论四种,两个概率相乘。
打的时候,觉得从零开始很别扭,就初始化出了1的
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 2000
using namespace std;
int n,m,v,e,r1[N+5],r2[N+5],dis[305][305];
int fa[N+5];
double luck[N+5],f[N+5][N+5][2],unluck[N+5];
void init()
{
memset(dis,0x3f,sizeof(dis));
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j][0]=f[i][j][1]=1e18;
for(int i=1;i<=n;i++)
scanf("%d",&r1[i]);
for(int i=1;i<=n;i++)
scanf("%d",&r2[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&luck[i]),unluck[i]=1-luck[i];
int x,y,z;
for(int i=1;i<=e;i++)
{
scanf("%d%d%d",&x,&y,&z);
dis[x][y]=min(dis[x][y],z);
dis[y][x]=dis[x][y];
}
}
int yjn()
{
//freopen("classrooma.in","r",stdin);
//freopen("classrooma.out","w",stdout);
init();
for(int i=1;i<=v;i++)dis[i][i]=0;
for(int k=1;k<=v;k++)
for(int i=1;i<=v;i++)
if(i!=k)
for(int j=1;j<=v;j++)
if(j!=i&&k!=j)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
f[1][0][0]=f[1][1][1]=0.0;
for(int i=1;i<n;i++)
for(int j=0;j<=m;j++)
{
f[i+1][j][0]=min(f[i+1][j][0],f[i][j][0]+dis[r1[i]][r1[i+1]]);
f[i+1][j][0]=min(f[i+1][j][0],f[i][j][1]+luck[i]*dis[r2[i]][r1[i+1]]+unluck[i]*dis[r1[i]][r1[i+1]]);
if(j<m)
{
f[i+1][j+1][1]=min(f[i+1][j+1][1],f[i][j][0]+luck[i+1]*dis[r1[i]][r2[i+1]]+unluck[i+1]*dis[r1[i]][r1[i+1]]);
f[i+1][j+1][1]=min(f[i+1][j+1][1],f[i][j][1]+luck[i]*unluck[i+1]*dis[r2[i]][r1[i+1]]+unluck[i]*unluck[i+1]*dis[r1[i]][r1[i+1]]+unluck[i]*luck[i+1]*dis[r1[i]][r2[i+1]]+luck[i]*luck[i+1]*dis[r2[i]][r2[i+1]]);
}
}
double s=1e18;
for(int i=0;i<=m;i++)
s=min(s,min(f[n][i][0],f[n][i][1]));
printf("%0.2lf",s);
}
int qty=yjn();
int main(){;}