终于有一道没有多组数据的题啦!
看了看题解,他们的状态转移都打得好长……
所以索性就不看了!
这其实就是个比较裸的期望DP
但是我太菜了以至于我忍不住看题解
首先跑一遍Floyd求全局最短路没有毛病
然后定义状态:
double f[i][j][k]
为前
i
i
i堂课中请求换了
j
j
j堂,上学时每一天去到第
i
i
i堂课的教室后,总共已经走过的路程,其中
k
=
1
k=1
k=1表示第
i
i
i堂课申请换课,
k
=
0
k=0
k=0表示没申请
int map[i][j]
表示
i
⟶
j
i\longrightarrow j
i⟶j或是
j
⟶
i
j\longrightarrow i
j⟶i的距离
int c[i],d[i]
如题意
double p[i]
为题中k[i]
然后我们来推转移方程:
-
这个点没有申请
没有申请的话 j j j就不会增加,但是距离什么的还得看前一堂课有没有申请
f[i][j][0]
- 如果前一堂课有申请
f[i-1][j][1]
还得讨论- 如果申请成功了
map[ d[i-1] ] [ c[i] ]
(乘上几率)*p[i-1]
- 如果失败
map[ c[i-1] ] [ c[i] ]*(1-p[i-1])
- 如果申请成功了
- 没有申请
f[i-1][j][0]
那就不用乘上几率了
map[ c[i-1] ] [ c[i] ]
前面这些连起来就是:
f[i][j][0]=min(
f[i-1][j][1] + map[ d[i-1] ][ c[i] ] * p[i-1] + map[ c[i-1] ][ c[i] ] * (1-p[i-1]),
f[i-1][j][0] + map[ c[i-1] ][ c[i] ]
)
- 如果前一堂课有申请
-
申请了
这下情况就复杂了,但是我们还是可以应对的
f[i][j][1]
- 上一节课申请
f[i-1][j-1][1]
- 两节都成功
map[ d[i-1] ][ d[i] ] * p[i-1] * p[i]
- 上节成功这节失败
map[ d[i-1] ][ c[i] ] * p[i-1] * (1-p[i])
- 上节失败这节成功
map[ c[i-1] ][ d[i] ] * (1-p[i-1]) * p[i]
- 都失败
map[ c[i-1] ][ c[i] ] * (1-p[i-1]) * (1-p[i])
- 两节都成功
- 没有
f[i-1][j-1][0]
- 这节成功
map[ c[i-1] ][ d[i] ] * p[i]
- 这节失败
map[ c[i-1] ][ c[i] ] * (1-p[i])
- 这节成功
终于打完了!
总结起来就有点长了:
f[i][j][1]=min(
f[i-1][j-1][1]+
map[ d[i-1] ][ d[i] ] * p[i-1] * p[i]+
map[ d[i-1] ][ c[i] ] * p[i-1] * (1-p[i])+
map[ c[i-1] ][ d[i] ] * (1-p[i-1]) * p[i]+
map[ c[i-1] ][ c[i] ] * (1-p[i-1]) * (1-p[i])
,
f[i-1][j-1][0]+
map[ c[i-1] ][ d[i] ] * p[i]
map[ c[i-1] ][ c[i] ] * (1-p[i])
)
至此,转移方程推理全部他娘的结束
(我终于明白为什么STL里面的函数传参表要分开几行还带着缩进打了) - 上一节课申请
然后就可以AC了
注意边界条件
顺带一提我一开始Floyd还打错了
#include<cstdio>
#include<cstring>
using namespace std;
inline double min(const double a,const double b)
{return a<b?a:b;}
inline void read(int &x)
{
x=0;register char c=getchar();
while(c<48||57<c) c=getchar();
for(;48<=c&&c<=57;c=getchar()) x=x*10+(c&15);
}
int map[310][310];
namespace graph
{
int n,m;
void graph()
{
memset(map,63,sizeof(map));
for(int i=1;i<=n;i++)
map[i][i]=0;
int x,y,c;
for(int i=1;i<=m;i++)
{
read(x);read(y);read(c);
map[y][x]=map[x][y]=min(map[x][y],c);
}
for(int k=1;k<=n;k++)//k要放最外面QAQ
for(int i=1;i<=n;i++)
if(i!=k)
for(int j=1;j<=n;j++)
if(i!=j&&k!=j)
map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
}
};
int c[2100],d[2100];
double p[2100],f[2100][2100][2];
int main()
{
int n,m;read(n);read(m);read(graph::n);read(graph::m);
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",p+i);
graph::graph();
memset(f,127,sizeof(f));//这是double的极大值
f[1][0][0]=f[1][1][1]=0;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=min(i,m);j++)
{
if(j<i)f[i][j][0]=min(
f[i-1][j][1]+map[d[i-1]][c[i]]*p[i-1]+map[c[i-1]][c[i]]*(1-p[i-1]),
f[i-1][j][0]+map[c[i-1]][c[i]]
);
if(0<j)f[i][j][1]=min(
f[i-1][j-1][1]+
map[d[i-1]][d[i]]*p[i-1]*p[i]+
map[d[i-1]][c[i]]*p[i-1]*(1-p[i])+
map[c[i-1]][d[i]]*(1-p[i-1])*p[i]+
map[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i]),
f[i-1][j-1][0]+
map[c[i-1]][d[i]]*p[i]+
map[c[i-1]][c[i]]*(1-p[i])
);
}
}
double ans=1e308;
for(int i=0;i<=m;i++)
ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2lf",ans);
return 0;
}