1. 程式人生 > >NOIP 2016 D1T3 換教室

NOIP 2016 D1T3 換教室

為什麼我覺得這年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; }
醜程式碼