题目描述
NOIP2016D1T3
Solution
题目巨长无比,数据解释巨长无比,数据表巨长无比,感觉这才是noip应该有的样子
期望dp,设f[i][j][1/0]表示第i时刻用了j次换教室的机会,现在换/不换的期望。跑一个floyd找最短路,枚举转移就可以了。
期望简而言之就是枚举出所有情况,把每一种情况的权值*概率再相加就是总的期望。对于这道题目就是判断一下第i-1天是否成功、第i天是否成功
一个坑点就是n和v代表着不同的东西,第一次不注意floyd跑挂了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define INF 0x7fffffff
#define N 2005
using namespace std;
double f[N][N][2],p[N];
int dis[N][N],c[N],d[N];
int n,m,v,e;
void dp() {
rep(i,0,n) {
rep(j,0,m) {
f[i][j][0]=f[i][j][1]=INF;
}
}
f[1][1][1]=0;
f[1][0][0]=0;
rep(i,2,n) {
rep(j,0,min(i,m)) {
f[i][j][0]=min(f[i][j][0],(double)(f[i-1][j][0]+dis[c[i-1]][c[i]]));
if (j>0) {
f[i][j][0]=min(f[i][j][0],(double)
(f[i-1][j][1]+dis[d[i-1]][c[i]])*p[i-1]+
(f[i-1][j][1]+dis[c[i-1]][c[i]])*(1-p[i-1]));
f[i][j][1]=min(f[i][j][1],(double)
(f[i-1][j-1][0]+dis[c[i-1]][d[i]])*p[i]+
(f[i-1][j-1][0]+dis[c[i-1]][c[i]])*(1-p[i]));
}
if (j>1) {
f[i][j][1]=min(f[i][j][1],(double)
(f[i-1][j-1][1]+dis[c[i-1]][c[i]])*(1-p[i-1])*(1-p[i])+
(f[i-1][j-1][1]+dis[d[i-1]][c[i]])*p[i-1]*(1-p[i])+
(f[i-1][j-1][1]+dis[c[i-1]][d[i]])*(1-p[i-1])*p[i]+
(f[i-1][j-1][1]+dis[d[i-1]][d[i]])*p[i-1]*p[i]);
}
}
}
double ans=INF;
for (int i=0;i<=m;i++)
ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2lf",ans);
}
void floyd() {
rep(k,1,v) {
rep(i,1,v) {
rep(j,1,v) {
if (i!=j&&i!=k&&j!=k&&dis[i][k]+dis[k][j]<dis[i][j]) {
dis[i][j]=dis[i][k]+dis[k][j];
}
}
}
}
}
void init() {
fill(dis,63);
scanf("%d%d%d%d",&n,&m,&v,&e);
rep(i,1,v) dis[i][i]=0;
rep(i,1,n) scanf("%d",&c[i]);
rep(i,1,n) scanf("%d",&d[i]);
rep(i,1,n) scanf("%lf",&p[i]);
rep(i,1,e) {
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
dis[x][y]=min(dis[x][y],w);
dis[y][x]=min(dis[y][x],w);
}
}
int main(void) {
init();
floyd();
dp();
return 0;
}