P1850 [NOIP2016 提高组] 换教室

[NOIP2016 提高组] 换教室 - 洛谷

题目大意:学校有v个教室,要上n节课,学校里有e条道路连接教室,每节课还有一个可以替换的教室,并且有ki的概率替换原有教室,现有m次申请替换教室的机会,问经过的路径的期望的最小值

思路:期望dp,首先用floyd算法枚举每个点作为拐点,求出每两间教室之间的最短距离,然后设置状态dp[i][j][k]表示上了i节课换了j次教室,k表示当前课换没换教室,在转移时,如果当前课没换,只要考虑前一节课有没有换,换了有没有成功,如果当前课换了教室,要考虑上一节课换没换,换了成没成功和当前课成没成功

#include<bits/stdc++.h>
using namespace std;
int n, m, v, e;
const int N = 2005;
int ma[305][505];
int c[N][N];
double k[N];
double dp[N][N][2];
const double INF = 1e9;
int main()
{
	scanf("%d%d%d%d", &n, &m, &v, &e);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &c[i][0]);//安排上课的教室
	}
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &c[i][1]);//可供选择的教室
	}
	for (int i = 1; i <= n; i++)
	{
		scanf("%lf", &k[i]);//更换教室的成功率
	}
	memset(ma, 63, sizeof ma);
	for (int i = 1; i <= e; i++)
	{
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);//从u到v有一条长为w的路
		ma[u][v] = ma[v][u] = min(ma[u][v], w);//同样两个点可能有多条路
	}
	for (int k = 1; k <= v; k++)
	{
		for (int i = 1; i <= v; i++)
		{
			for (int j = 1; j <= v; j++)
			{
				ma[i][j] = min(ma[i][j], ma[i][k] + ma[k][j]);
				//floyd算法,枚举每个点作为拐点,求出每两个点之间的最短路
			}
		}
	}
	for (int i = 1; i <= v; i++)
	{
		ma[i][i]  = 0;//同教室间路线长度为0
	}
	for (int i = 0; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			dp[i][j][0] = dp[i][j][1] = INF;
		}//求最小值,先把所有值初始化成最大
	}
	dp[1][0][0] = dp[1][1][1] = 0;
	for (int i = 2; i <= n; i++)
	{
		dp[i][0][0] = dp[i - 1][0][0] + ma[c[i - 1][0]][c[i][0]];
		//不换教室的话,期望就是上一时间段没换教室加上个教室到这个教室的距离
		for (int j = 1; j <= min(i, m); j++)
		{
			int o1 = c[i - 1][0], o2 = c[i - 1][1], o3 = c[i][0], o4 = c[i][1];
			dp[i][j][0] = min(dp[i - 1][j][0] + ma[o1][o3], dp[i - 1][j][1] + ma[o2][o3] * k[i - 1] + ma[o1][o3] * (1 - k[i - 1]));
			//这次没换的期望就是上一次没换,或者上一次换了且成功,或者上一次换了但没成功
			dp[i][j][1] = min(dp[i - 1][j - 1][0] + ma[o1][o4] * k[i] + ma[o1][o3] * (1 - k[i]), dp[i - 1][j - 1][1] + ma[o2][o3] * k[i - 1] * (1 - k[i]) + ma[o1][o3] * (1 - k[i - 1]) * (1 - k[i]) + ma[o1][o4] * (1 - k[i - 1]) * k[i] + ma[o2][o4] * k[i - 1] * k[i]);
			//这次换了的期望就是上一次没换且这次换失败了,或者上一次没换但这次换成功了
			//或者上一次换了没成功但这次成功了,或者上一次换了没成功这次也成功
			//或者上一次换了成功了但这次没成功,或者上一次换了没成功但这次成功了
		}		
	}
	double ans = INF;
	for (int i = 0; i <= m; i++)
	{
		ans = min(ans, min(dp[n][i][0], dp[n][i][1]));
	}
	printf("%.2lf", ans);
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timidcatt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值