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; }