题目传送门
题意: 有 n n n节课,每节课在相同时间不同教室上( c [ i ] c[i] c[i]和 d [ i ] d[i] d[i]),总共有 v v v个教室, e e e条边,在学期开始之前,你可以向学校申请调换教室(由 c [ i ] c[i] c[i]换到 d [ i ] d[i] d[i]),第 i i i节课调换成功的概率是 k [ i ] k[i] k[i],你最多可以选择 m m m节课进行调换,并且不同课之间调换是否成功不受影响。我们想知道从第一节课的教室到第 n n n节课的教室,我们走的最短的路的期望是多少?
思路: 先用 F l o y d Floyd Floyd把每两个点之间的最短距离处理一下。然后我们用 f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]表示处理完前 i i i节课,选择了 j j j节课申请调换,第 i i i节课是否申请(0/1)时的期望最短路径。那么我们就可以写出状态转移方程。
-
double d1=1.0*a[c[i-1]][c[i]]; double d2=1.0*a[c[i-1]][d[i]]; double d3=1.0*a[d[i-1]][c[i]]; double d4=1.0*a[d[i-1]][d[i]];
-
f [ i ] [ j ] [ 0 ] = m i n ( f [ i − 1 ] [ j ] [ 0 ] + 1.0 ∗ d 1 , f [ i − 1 ] [ j ] [ 1 ] + d 1 ∗ ( 1 − k [ i − 1 ] ) + d 3 ∗ k [ i − 1 ] ) ; f[i][j][0]=min(f[i-1][j][0]+1.0*d1,f[i-1][j][1]+d1*(1-k[i-1])+d3*k[i-1]); f[i][j][0]=min(f[i−1][j][0]+1.0∗d1,f[i−1][j][1]+d1∗(1−k[i−1])+d3∗k[i−1]);
-
f [ i ] [ j ] [ 1 ] = m i n ( f [ i − 1 ] [ j − 1 ] [ 0 ] + d 1 ∗ ( 1 − k [ i ] ) + d 2 ∗ k [ i ] , f [ i − 1 ] [ j − 1 ] [ 1 ] + d 1 ∗ ( 1 − k [ i − 1 ] ) ∗ ( 1 − k [ i ] ) + d 2 ∗ ( 1 − k [ i − 1 ] ) ∗ k [ i ] + d 3 ∗ k [ i − 1 ] ∗ ( 1 − k [ i ] ) + d 4 ∗ k [ i − 1 ] ∗ k [ i ] ) ; f[i][j][1]=min(f[i-1][j-1][0]+d1*(1-k[i])+d2*k[i],f[i-1][j-1][1]+d1*(1-k[i-1])*(1-k[i])+d2*(1-k[i-1])*k[i]+d3*k[i-1]*(1-k[i])+d4*k[i-1]*k[i]); f[i][j][1]=min(f[i−1][j−1][0]+d1∗(1−k[i])+d2∗k[i],f[i−1][j−1][1]+d1∗(1−k[i−1])∗(1−k[i])+d2∗(1−k[i−1])∗k[i]+d3∗k[i−1]∗(1−k[i])+d4∗k[i−1]∗k[i]);
最后找答案就很简单了。
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define lowbit(x) x&-x
#define pii pair<int,int>
#define ull unsigned long long
#define pdd pair<double,double>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read()
{
int x=0,f=1;
char ch=gc();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=gc();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=gc();
}
return x*f;
}
using namespace std;
const int N=3e4+666;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-7;
const double PI=acos(-1);
int c[N],d[N],a[333][333];
double k[N],f[2222][2222][2];
signed main()
{
int n,m,v,e;
cin>>n>>m>>v>>e;
for(int i=1; i<=n; i++)
cin>>c[i];
for(int i=1; i<=n; i++)
cin>>d[i];
for(int i=1; i<=n; i++)
cin>>k[i];
for(int i=0; i<333; i++)
for(int j=0; j<333; j++)
a[i][j]=(i==j?0:inf);
for(int i=0;i<2222;i++)
for(int j=0;j<2222;j++)
f[i][j][0]=f[i][j][1]=1e9;
for(int i=1; i<=e; i++)
{
int x,y,z;
cin>>x>>y>>z;
a[x][y]=min(a[x][y],z);
a[y][x]=min(a[y][x],z);
}
for(int p=1; p<=v; p++)
for(int i=1; i<=v; i++)
for(int j=1; j<=v; j++)
a[i][j]=min(a[i][p]+a[p][j],a[i][j]);
double res=1e9;
f[1][0][0]=f[1][1][1]=0.0;
for(int i=2; i<=n; i++)
{
for(int j=0; j<=min(i,m); j++)
{
double d1=1.0*a[c[i-1]][c[i]];
double d2=1.0*a[c[i-1]][d[i]];
double d3=1.0*a[d[i-1]][c[i]];
double d4=1.0*a[d[i-1]][d[i]];
f[i][j][0]=min(f[i-1][j][0]+1.0*d1,f[i-1][j][1]+d1*(1-k[i-1])+d3*k[i-1]);
if(j!=0)
f[i][j][1]=min(f[i-1][j-1][0]+d1*(1-k[i])+d2*k[i],f[i-1][j-1][1]+d1*(1-k[i-1])*(1-k[i])+d2*(1-k[i-1])*k[i]+d3*k[i-1]*(1-k[i])+d4*k[i-1]*k[i]);
}
}
for(int i=0;i<=m;i++)
res=min(res,min(f[n][i][0],f[n][i][1]));
printf("%.2f\n",res);
return 0;
}