【NOIP16提高组】换教室

33 篇文章 0 订阅
23 篇文章 0 订阅

 【题目链接】

          点击打开链接

 【算法】

          概率DP

          先跑一遍floyed,求出每个教室之间的最短路径,存在数组dist[][]中,时间复杂度O(V^3)

          设计状态,f[i][j][k]表示当前选到第i个教室,已经选了j个教室,当前这个教室选不选(0..1)

          那么,状态转移方程是什么呢?

          假设当前选到第i个教室,已经选了j个教室,那么,如果不选这个教室,则状态转移方程为

          f[i][j][0] = max{f[i-1][j][0]+dist[c[i-1]][c[i]],f[i-1][j][1]+dist[c[i-1]][c[i]]*(1-k[i-1])+dist[d[i-1]][c[i]]*k[i-1]}

      如果选这个教室,则状态转移方程是

      f[i][j][1] = min{f[i-1][j-1][0]+dist[c[i-1]][d[i]]*k[i]+dist[c[i-1]][c[i]]*(1-k[i],f[i-1][j-1][1]+dist[d[i-1]][d[i]]*k[i-1]*k[i]+dist[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dist[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dist[d[i-1]][c[i]]*k[i-1]*(1-k[i])}

 

      于是这道题便迎刃而解了!

      【代码】

   

#include<bits/stdc++.h>
using namespace std;
#define MAXN 2000
#define MAXV 300

int i,j,k,n,m,v,e,a,b,w;
int dist[MAXV+10][MAXV+10],c[MAXN+10],d[MAXN+10];
double P[MAXN+10],dp[MAXN+10][MAXN+10][2];
double ans = 2e9;

template <typename T> inline void read(T &x) {
		int f=1; x=0;
		char c = getchar(); 
		for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
		for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
		x *= f;
}

template <typename T> inline void write(T x) {
    if (x < 0) { putchar('-'); x = -x; }
    if (x > 9) write(x/10);
    putchar(x%10+'0');	
}

template <typename T> inline void writeln(T x) {
    write(x);
    puts("");	
}

int main() {
		
		read(n); read(m); read(v); read(e);
		for (i = 1; i <= v; i++) {
				for (j = 1; j <= v; j++) {
						if (i != j)
								dist[i][j] = 2e9;
				}
		}
 		for (i = 1; i <= n; i++) read(c[i]);
		for (i = 1; i <= n; i++) read(d[i]);
		for (i = 1; i <= n; i++) cin >> P[i];
		for (i = 1; i <= e; i++) {
				read(a); read(b); read(w);
				dist[a][b] = min(dist[a][b],w);
				dist[b][a] = min(dist[b][a],w);	
		}
	
		for (k = 1; k <= v; k++) {
				for (i = 1; i <= v; i++) {
						if (i == k) continue;
						if (dist[i][k] == 2e9) continue;
						for (j = 1; j <= v; j++) {
								if (dist[k][j] == 2e9) continue;
								if ((i == j) || (k == j)) continue;
								dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]);
						}
				}
		}	
		
		for (i = 1; i <= n; i++) {
				for (j = 0; j <= m; j++) {
						dp[i][j][0] = dp[i][j][1] = 2e9;
				}	
		}
		
		dp[1][0][0] = 0; dp[1][1][1] = 0;
		for (i = 2; i <= n; i++) {
				dp[i][0][0] = dp[i-1][0][0] + dist[c[i-1]][c[i]];
				for (j = 1; j <= min(i,m); j++) {
						dp[i][j][0] = min(dp[i-1][j][0]+dist[c[i-1]][c[i]],dp[i-1][j][1]+dist[c[i-1]][c[i]]*(1.0-P[i-1])+dist[d[i-1]][c[i]]*P[i-1]);
						dp[i][j][1] = min(dp[i-1][j-1][0]+dist[c[i-1]][d[i]]*P[i]*1.0+dist[c[i-1]][c[i]]*(1.0-P[i]),
															dp[i-1][j-1][1]+
															dist[d[i-1]][d[i]]*P[i-1]*P[i]*1.0+ 
															dist[c[i-1]][d[i]]*(1.0-P[i-1])*P[i]+ 
															dist[c[i-1]][c[i]]*(1.0-P[i-1])*(1.0-P[i])+ 
														        dist[d[i-1]][c[i]]*P[i-1]*(1-P[i])*1.0); 
				}	
		}
		
		for (i = 0; i <= m; i++) ans = min(ans,min(dp[n][i][0],dp[n][i][1]));
		cout<< fixed << setprecision(2) << ans << endl;
		
		return 0;
	
}

         

            

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值