传送门: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(){;}