NOIP 2016 D1T3 換教室
阿新 • • 發佈:2018-11-02
為什麼我覺得這年D1非常之喪……
看到題目有點暈……,反正發現v<=500之後先寫了floyd,不寫白不寫。
現在我們有任意兩點之間的最短路了,考慮dp(i表示考慮到第i個時間段)
f[i][j][0]=min(跑到c[i]的期望距離)
f[i][j][1]表示min(跑到c[i]的期望距離*(1-k[i])+跑到d[i]的期望距離*k[i] )(即假設在i交了申請跑到第i個教室的最短期望距離)
什麼意思呢?
先設 g[x] = 跑到x的期望距離
我們假設有 i 要從 i-1 轉移。
假若i-1處不交轉課申請,無論對於d[i]還是c[i] 我們肯定希望 g[c[i-1]] 越小越好。
假若i-1處交了轉課申請,同理
我們肯定希望 (g[c[i-1]]+dis[c[i-1]][c[i]])*(1-k[i-1])+(g[d[i-1]]+dis[d[i-1]][c[i]])*k[i-1] 以及
(g[c[i-1]]+dis[c[i-1]][d[i]])*(1-k[i-1])+(g[d[i-1]]+dis[d[i-1]][d[i]])*k[i-1]越小越好。
發現dis其實無法改變,考慮把dis刪去,得到g[c[i-1]]*(1-k[i-1])+g[d[i-1]]*k[i-1],我們要最小化的是它。
這時我們發現一個dp[i][j]其實需要維護兩個狀態才能滿足最優子結構的性質。
因此就有了上面的狀態表示,我們考慮n^2轉移即可,轉移方程不難想,但是很難寫……
程式碼(式子巨長,細節巨多,心力交瘁):
#include<cstdio> #include<cstring> #define min(a,b) (a<b?a:b) #define init(x,p) memset(x,p,sizeof(x)) int map[505][505]; int n,m,v,e,c[2005],d[2005]; double k[2005],dp[2005][2005][4]; void init_dp(); void floyd(); int main(){醜程式碼// freopen("xx.txt","r",stdin); init(map,0x3f); scanf("%d%d%d%d",&n,&m,&v,&e); for(int i=1;i<=n;++i){ scanf("%d",&c[i]); if(c[i]==0) return -1; } 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;i<=e;++i){ int a,b,cd; scanf("%d%d%d",&a,&b,&cd); map[a][b]=map[b][a]=min(map[b][a],cd); } for(int i=1;i<=v;++i) map[i][i]=0; floyd(); init_dp(); dp[1][0][0]=dp[1][0][1]=0; #define f map for(int i=2;i<=n;++i){ for(int j=0;j<=min(n,m);++j){ if(!j){ dp[i][j][0]=dp[i-1][j][0]+f[c[i-1]][c[i]]; dp[i][j][1]=f[c[i-1]][c[i]]*(1-k[i])+f[c[i-1]][d[i]]*k[i]+dp[i-1][j][0]; continue; } dp[i][j][0]=min( dp[i-1][j][0]+f[c[i-1]][c[i]], dp[i-1][j-1][1]+f[d[i-1]][c[i]]*(k[i-1])+f[c[i-1]][c[i]]*(1-k[i-1]) ); dp[i][j][1]=min( f[c[i-1]][c[i]]*(1-k[i])+f[c[i-1]][d[i]]*k[i]+dp[i-1][j][0], (f[d[i-1]][c[i]]*(k[i-1])+f[c[i-1]][c[i]]*(1-k[i-1]))*(1-k[i])+(f[d[i-1]][d[i]]*(k[i-1])+f[c[i-1]][d[i]]*(1-k[i-1]))*k[i]+dp[i-1][j-1][1] ); } } #undef f // printf("%.3f",min(f[n][j][])) double ans=1e10; for(int j=0;j<=m;++j){ ans=min(ans,dp[n][j][0]); if(j!=m) ans=min(ans,dp[n][j][1]); } printf("%.2lf\n",ans); return 0; } void floyd(){ for(int k=1;k<=v;++k) for(int i=1;i<=v;++i) for(int j=1;j<=v;++j) map[i][j]=min(map[i][k]+map[k][j],map[i][j]); return ; } void init_dp(){ for(int i=0;i<2005;++i) for(int j=0;j<2005;++j) dp[i][j][0]=dp[i][j][1]=1e8; }