1. 程式人生 > >【洛谷P1850】換教室

【洛谷P1850】換教室

main cst 思維 ans esp ostream () space cto

這個題是個裸的期望dp,因為點比較少,所以可以用floyd,但是開始我打的dijkstra,t了,而且我發現數據還輸不完,輸著輸著就停下了,換上floyd就好了……真是玄學

我們設dp[i][j][0/1]表示現在處理到了第i個教室,提交了j個申請,這個點是否提交申請

對於第三維是0的時候,我們只要考慮上個點交過申請還是沒交過,但是當第3維為1的時候,我們還要考慮當前這個點申請通不通過和上個點的申請情況,有四種情況,比較難寫,但是思維難度不大

總的來說這個題還是很有難度的,我覺得我考場上要是碰到這個題還是直接跳過吧qwq

#include<iostream>
#include
<cstring> #include<cstdio> #include<vector> #include<queue> using namespace std; int tail,x[2020],y[2020],a,b,c,head[330],n,m,v,e,ans[2020][2020]; double gai[2020],dp[2020][2020][2],pri; void floyd()//求最短路,預處理 { for(int k=1;k<=v;k++) for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++) ans[i][j]=min(ans[i][j],ans[i][k]+ans[j][k]); } int main() { scanf("%d%d%d%d",&n,&m,&v,&e); for(int i=1;i<=n;i++) scanf("%d",&y[i]); for(int i=1;i<=n;i++) scanf("%d",&x[i]); for(int i=1;i<=n;i++) scanf(
"%lf",&gai[i]); memset(ans,0x3f,sizeof(ans)); for(int i=1;i<=v;i++) ans[i][i]=0; for(int i=1;i<=e;i++) scanf("%d%d%d",&a,&b,&c),ans[a][b]=ans[b][a]=min(c,ans[b][a]); floyd(); memset(dp,127,sizeof(dp)); dp[0][0][0]=dp[1][0][0]=dp[1][1][1]=0;//初始化,一定要記得把dp[1][1][1]賦值為0!!! for(int i=2;i<=n;i++)//一個點都不申請的時候 dp[i][0][0]=ans[y[i-1]][y[i]]+dp[i-1][0][0]; for(int i=2;i<=n;i++) for(int j=1;j<=min(m,i);j++) { dp[i][j][0]=min(dp[i-1][j][0]+ans[y[i-1]][y[i]],dp[i][j][0]);//當這個點不取的時候很簡單,就看上一個點是否備取就行 dp[i][j][0]=min(dp[i-1][j][1]+(ans[x[i-1]][y[i]]*gai[i-1]+ans[y[i-1]][y[i]]*(1-gai[i-1])),dp[i][j][0]); dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][0]+(ans[y[i-1]][x[i]]*gai[i]+ans[y[i-1]][y[i]]*(1-gai[i])));//當這個點取的時候,要考慮四種情況,a取/不取 b取/不取 dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][1]+ ans[x[i-1]][x[i]]*gai[i-1]*gai[i] +ans[x[i-1]][y[i]]*gai[i-1]*(1-gai[i]) +ans[y[i-1]][x[i]]*gai[i]*(1-gai[i-1]) +ans[y[i-1]][y[i]]*(1-gai[i])*(1-gai[i-1])); } pri=dp[n][0][0]; for(int i=1;i<=m;i++)//取個最小值 pri=min(pri,min(dp[n][i][0],dp[n][i][1])); printf("%.2lf",pri); }

【洛谷P1850】換教室