NOIP2016换教室
Description
Analysis
不得不承认看了题之后确实想到的是概率dp。。。
由于博主太懒而且这篇题解挺详细
我就只记录一下没讲到的地方
f[i][j][1/0]是上了i节课,当前换了j次(包括本节课)教室的本节课的选择(0/1)
只给f[1][1][1],[1][0][0]两项赋初值为0
强调一下f[i][j][k]是已经上了i节课,换了j次教室(包括第i节课),这节课是否换教室
所以只有上第一节课换教室(f[1][1][1])和不换教室(f[1][0][0])两种情况要初始化且初始化为0
注意循环中j=0要分开
代码
#include<cstdio>
#include<iostream>
using namespace std;
const int INF=800000000;
int n,m,v,e;
int c[2005],d[2005],dis[305][305];
double k[2005],f[2005][2005][2];
inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
int main(){
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=1;i<=n;i++)c[i]=read();
for(int i=1;i<=n;i++)d[i]=read();
for(int i=1;i<=n;i++)cin>>k[i];
for (int i=1;i<=v;i++)
for (int j=1;j<i;j++)
dis[j][i]=dis[i][j]=INF;
for(int i=1;i<=e;i++){
int cn=read(),cm=read(),cw=read();
dis[cn][cm]=dis[cm][cn]=min(dis[cn][cm],cw);
}
//输入
for(int l=1;l<=v;l++){
for(int i=1;i<=v;i++){
for(int j=1;j<i;j++){
if(dis[i][j]>dis[i][l]+dis[l][j])
dis[j][i]=dis[i][j]=dis[i][l]+dis[l][j];
}
}
}
//Floyd
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j][0]=f[i][j][1]=INF;
}
}
f[1][1][1]=f[1][0][0]=0;
for (int i=2;i<=n;i++)
for (int j=0;j<=m;j++){
f[i][j][0]= min(f[i-1][j][1]+ k[i-1]*dis[d[i-1]][c[i]]+ (1-k[i-1])*dis[c[i-1]][c[i]],
f[i-1][j][0] +dis[c[i-1]][c[i]]);
if (j!=0)
f[i][j][1]=min(f[i-1][j-1][1]+k[i-1]*k[i]*dis[d[i-1]][d[i]]+k[i-1]*(1-k[i])*dis[d[i-1]][c[i]]+(1-k[i-1])*k[i]*dis[c[i-1]][d[i]]+(1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]],
f[i-1][j-1][0]+k[i]*dis[c[i-1]][d[i]]+(1-k[i])*dis[c[i-1]][c[i]]);
}
//dp
double ans=INF;
for (int i=0;i<=m;i++)
for (int j=0;j<=1;j++){
ans=min(ans,f[n][i][j]);
}
printf("%.2lf",ans);
return 0;
}
本文版权归作者LHR,欢迎转载,但未经LHR同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则LHR保留追究法律责任的权利。