[NOIp2016]换教室

Description

Luogu1850

Solution

其实只要理解了什么叫期望就可以轻松的DP出来这道题了。

状态设计为(f(i,j,k))表示前(i)个点,换了(j)个,路径的期望长度,其中(k=0)表示(i)不换,(k=1)表示(i)换。
转移为:

[f(i, j, 0) = \ mbox{min} (f(i-1, j, 0) + dis(c_{i-1}, c_i),\ f(i-1, j, 1) + (1-k_{i-1})dis(c_{i-1}, c_i) + k_{i-1}dis(d_{i-1}, c_i) ) ]

[f(i, j, 1) =\ mbox{min} (f(i-1, j, 0) + (1-k_i)dis(c_{i-1}, c_i) + k_i dis(c_{i-1}, d_i), \ f(i-1, j, 1) + (1-k_{i-1})(1-k_i)dis(c_{i-1}, c_i) + k_{i-1}(1-k_i)dis(d_{i-1}, c_i) + k_i(1-k_{i-1})dis(c_{i-1}, d_i) + k_{i-1}k_idis(d_{i-1}, d_i) ) ]

Code

#include <cstdio>
#include <cstring>
#include <algorithm>

const int V = 310;
const int N = 2010;

int dis[V][V];
int n, m, v, e;
int c[N], d[N];
double k[N], f[N][N][2];

int main() {
	memset(dis, 0x3f, sizeof dis);
	scanf("%d%d%d%d", &n, &m, &v, &e);
	for (int i = 1; i <= n; ++i) scanf("%d", &c[i]);
	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, x, y, z; i <= e; ++i) {
		scanf("%d%d%d", &x, &y, &z);
		dis[x][y] = dis[y][x] = std::min(dis[x][y], z);
	}
	for (int i = 1; i <= v; ++i) dis[i][i] = 0;
	for (int K = 1; K <= v; ++K)
		for (int i = 1; i <= v; ++i)
			for (int j = 1; j <= v; ++j)
				if (dis[i][j] > dis[i][K] + dis[K][j])
					dis[i][j] = dis[i][K] + dis[K][j];
	// printf("%d
", dis[1][2]);
	for (int i = 1; i <= n; ++i) for (int j = 0; j <= m; ++j) f[i][j][0] = f[i][j][1] = 1e8;
	f[1][0][0] = f[1][1][1] = 0;
	for (int i = 2; i <= n; ++i) {
		for (int j = 0; j <= m; ++j) if (j <= i) {
			if (j <= i - 1)
				f[i][j][0] = std::min( 
					f[i-1][j][0] + dis[c[i]][c[i-1]], 
					f[i-1][j][1] + dis[c[i]][c[i-1]] * (1.0 - k[i-1]) + dis[c[i]][d[i-1]] * k[i-1]
				);
			if (j > 0) 
				f[i][j][1] = std::min(
					f[i-1][j-1][0] + dis[d[i]][c[i-1]] * k[i] + dis[c[i]][c[i-1]] * (1.0-k[i]),
					f[i-1][j-1][1] + dis[d[i]][d[i-1]] * k[i] * k[i-1] + dis[d[i]][c[i-1]] * k[i] * (1.0-k[i-1]) + dis[c[i]][d[i-1]] * (1.0 - k[i]) * k[i-1] + dis[c[i]][c[i-1]] * (1.0 - k[i]) * (1.0 - k[i-1]) 
				);
		}
	}
	double ans = f[n][0][0];
	for (int i = 1; i <= m; ++i) {
		ans = std::min(ans, std::min(f[n][i][0], f[n][i][1]));
	}
	printf("%.2lf
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/wyxwyx/p/noip201613.html