原題鏈接:https://loj.ac/problem/2360
換教室
題目描述
對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。
在可以選擇的課程中,有節課程安排在個時間段上。在第個時間段上,兩節內容相同的課程同時在不同的地點進行,其中,牛牛預先被安排在教室上課,而另一節課程在教室進行。
在不提交任何申請的情況下,學生們需要按時間段的順序依次完成所有的節安排好的課程。如果學生想更換第i節課程的教室,則需要提出申請。若申請通過,學生就可以在第個時間段去教室上課,否則仍然在教室上課。
由於更換教室的需求太多,申請不一定能獲得通過。通過計算,牛牛發現申請更換第節課程的教室時,申請被通過的概率是一個已知的實數,並且對於不同課程的申請,被通過的概率是互相獨立的。
學校規定,所有的申請只能在學期開始前一次性提交,並且每個人只能選擇至多節課程進行申請。這意味着牛牛必須一次性決定是否申請更換每節課的教室,而不能根據某些課程的申請結果來決定其他課程是否申請;牛牛可以申請白己最希望更換教室的門課程,也可以不用完這個申請的機會,甚至可以一門課程都不申請。
因爲不同的課程可能會被安排在不同的教室進行,所以牛牛需要利用課問時間從一間教室趕到另一間教室。
牛牛所在的大學有個教室,有條道路。每條道路連接兩間教室,並且是可以雙向通行的。由於道路的長度和擁堵程度不同,通過不同的道路耗費的體力可能會有所不同。當第()節課結束後,牛牛就會從這節課的教室出發,選擇一條耗費體力最少的路徑前往下一節課的教室。
現在牛牛想知道,申請哪幾門課程可以使他因在教室問移動耗費的體力值的總和的期望值最小,請你幫他求出這個最小值。
輸入格式
第一行四個整數 。表示這個學期內的時間段的數量;表示牛牛最多可以申請更換多少節課程的教室;表示牛牛學校裏教室的數量;表示牛牛的學校裏道路的數量。
第二行個正整數,第()個正整數表示,即第個時間段牛牛被安排上課的教室;保證。
第三行個正整數,第()個正整數表示 ,即第個時間段另一間上同樣課程的教室;保證。
第四行個實數,第()個實數表示,即牛牛申請在第個時間段更換教室獲得通過的概率。保證。
接下來行,每行三個正整數,表示有一條雙向道路連接教室 ,通過這條道路需要耗費的體力值是;保證。
保證,,,。
保證通過學校裏的道路,從任何一間教室出發,都能到達其他所有的教室。
保證輸入的實數最多包含位小數。
輸出格式
輸出一行,包含一個實數,四舎五入精確到小數點後恰好位,表示答案。你的輸出必須和標準輸出完全一樣纔算正確。
測試數據保證四舎五入後的答案和準確答案的差的絕對值不大於 。(如果你不知道什麼是浮點誤差,這段話可以理解爲:對於大多數的算法,你可以正常地使用浮點數類型而不用對它進行特殊的處理)
樣例
輸入樣例
3 2 3 3
2 1 2
1 2 1
0.8 0.2 0.5
1 2 5
1 3 3
2 3 1
輸出樣例
2.80
數據範圍與提示
。
代碼
表示考慮前節課,申請換了節課,第節課是/否申請了調換。
然後轉移就非常自然了,只是有點小長。。。
對於申請了調換的教室,我們就要考慮調換成功/失敗兩種情況,加上當前情況的距離乘以出現概率,取即可。
代碼
#include<bits/stdc++.h>
using namespace std;
const int M=2005,N=305;
int c[M],d[M],dis[N][N],n,m,v,e;
double k[M],dp[M][M][2],ans=1e200;
void in()
{
memset(dis,63,sizeof(dis));
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=1;i<=n;++i)scanf("%d",&c[i]);
for(int i=1;i<=n;++i)scanf("%d",&d[i]);
for(int i=1;i<=n;++i)scanf("%lf",&k[i]);
for(int i=1,a,b,w;i<=e;++i)
scanf("%d%d%d",&a,&b,&w),dis[a][b]=min(dis[a][b],w),dis[b][a]=min(dis[b][a],w);
}
void ac()
{
for(int p=1;p<=v;++p)for(int i=1;i<=v;++i)for(int j=1;j<=v;++j)
if(dis[i][p]+dis[p][j]<dis[i][j])dis[i][j]=dis[i][p]+dis[p][j];
for(int i=1;i<=v;++i)dis[i][0]=dis[0][i]=dis[i][i]=0;
memset(dp,127,sizeof(dp));dp[1][0][0]=dp[1][1][1]=0;
for(int i=2,j;i<=n;++i)for(dp[i][0][0]=dp[i-1][0][0]+dis[c[i-1]][c[i]],j=1;j<=min(i,m);++j)
{
dp[i][j][0]=min(dp[i][j][0],min(dp[i-1][j][0]+dis[c[i-1]][c[i]],dp[i-1][j][1]+dis[c[i-1]][c[i]]*(1-k[i-1])+dis[d[i-1]][c[i]]*k[i-1]));
dp[i][j][1]=min(dp[i][j][1],min(dp[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1-k[i])+dis[c[i-1]][d[i]]*k[i],dp[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dis[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[d[i-1]][d[i]]*k[i-1]*k[i]));
}
for(int i=0;i<=m;++i)ans=min(ans,min(dp[n][i][0],dp[n][i][1]));
printf("%.2lf",ans);
}
int main(){in(),ac();}