2016 Noip Day1 T3 換教室 【概率DP+Floyd】


題目: https://vijos.org/p/2005   分析: 這個題就是在不斷地蒙你,先給普通的DP套了一個假的概率的外殼,再把弗洛伊德藏在教室和體力的關系間。看起來復雜嚇死人,實際上並沒有牽扯什么優化或是高級算法。 所謂的概率,就是給正常的路徑值乘了一個限定值,只不過要注意走什么路這個限定值不同。 我們用f [ i ] [ j ] [ 1 ] 表示考慮前 i 個時間段,已經申請了j 個教室的交換,並且當前教室申請的最小體力消耗。 我們用f [ i ] [ j ] [ 0 ] 表示考慮前 i 個時間段,已經申請了j 個教室的交換,並且當前教室不申請的最小體力消耗。首先肯定要預處理出來所有教室之間的最短路徑,再進行DP,此時分情況討論;(所有變量名與題目一致)1、當前教室不打算申請:( A 為原本教室, A'為備份教室,B 同理)2016   Noip Day1 T3   換教室 【概率DP+Floyed】 - linda_fcj - Captains Honor f [ i ] [ j ] [ 0 ] = min( f [ i ] [ j ] [ 0 ] , f [ i - 1 ] [ j ] [ 0 ] + w [ c [ i-1] ] [ c [ i ] ] ) ;表示前一個教室沒有申請;
 f [ i ] [ j ] [ 0 ] = min( f [ i ] [ j ] [ 0 ] , f [ i - 1 ] [ j ] [ 1 ] + w [ d [ i - 1 ] ] [ c [ i ] ] * k [ i - 1 ] + w [ c [ i  - 1 ] ] [c [ i ] ] * (1.0-k [ i-1] ));
綠色表示前一個教室申請了也通過了,藍色表示沒有通過。2、當前教室打算申請:2016   Noip Day1 T3   換教室 【概率DP+Floyed】 - linda_fcj - Captains Honorf [ i ] [ j ] [ 1 ] = min( f [ i ] [ j ] [ 1 ] , f [ i -1 ] [ j-1 ] [ 0 ] + k [ i ] *w[ c [i-1] ] [ d[i] ]+(1.0-k [ i ])*w [ c[i-1] ] [ c[i] ]); //前一個不申請
f [ i ] [ j ] [ 1 ] = min ( f [ i ] [ j ] [ 1 ] , f [ i -1 ] [ j-1 ] [ 1 ]
                                                 +k [ i-1 ] * k [ i ] * w [ d[i-1] ] [ d[i] ]          //     前一個選上了,后一個也選上了
                                                 +k [ i-1 ] * (1.0-k[i]) * w [ d[i-1] ] [ c[i] ]    //      前一個選上了,后一個沒選上
                                                 +(1.0 - k[i-1]) * k [ i ] * w [ c[i-1] ] [ d[i] ]  //      前一個沒選上,后一個選上了
                                                 +(1.0 - k [ i-1 ] ) * ( 1.0-k[i] ) * w [ c[i-1] ] [ c[i] ] );//前一個沒選上,后一個也沒選上
下面是參考代碼:
 
#include <iostream>
#include
<cstdio>
#include
<cstring>
#include
<algorithm>
#define inf 1000000007
using namespace std;
int n,m,v,e,a,b,ww;
int c[2020],d[2020],w[330][330];
double k[2020],f[2020][2020][3],ans=1.0*1e9;
int main()
{
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=1;i<=v+10;i++)
for(int j=0;j<=v+10;j++)
w[i][j]
=1e9;
for(int i=0;i<=304;i++) w[i][i]=0;
for(int i=1;i<=e;i++)
{
cin
>>a>>b>>ww;
w[a][b]
=w[b][a]=min(ww,w[a][b]);
}
for(int kk=1;kk<=v;kk++)
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
if(w[i][kk]+w[kk][j]<w[i][j])
w[i][j]
=w[i][kk]+w[kk][j];
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j][
0]=f[i][j][1]=1.0*1e9;
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++)
{
f[i][j][
0]=min(f[i][j][0],f[i-1][j][0]+w[c[i-1]][c[i]]);
f[i][j][
0]=min(f[i][j][0],f[i-1][j][1]+w[d[i-1]][c[i]]*k[i-1]+w[c[i-1]][c[i]]*(1.0-k[i-1]));
if(j>0)
{
f[i][j][
1]=min(f[i][j][1],f[i-1][j-1][0]+k[i]*w[c[i-1]][d[i]]+(1.0-k[i])*w[c[i-1]][c[i]]);
f[i][j][
1]=min(f[i][j][1],f[i-1][j-1][1]
+k[i-1]*k[i]*w[d[i-1]][d[i]]
+k[i-1]*(1.0-k[i])*w[d[i-1]][c[i]]
+(1.0-k[i-1])*k[i]*w[c[i-1]][d[i]]
+(1.0-k[i-1])*(1.0-k[i])*w[c[i-1]][c[i]]);
}
}
for(int i=0;i<=m;i++)
ans
=min(min(ans,f[n][i][1]),f[n][i][0]);
printf(
"%.2lf",ans);
return 0;
}
View Code

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com