[NOIP2016提高组]换教室

Posted Mrsrz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP2016提高组]换教室相关的知识,希望对你有一定的参考价值。

题目:洛谷P1850、UOJ#262、BZOJ4720、Vijos P2005。

题目大意:有n个时间段,第i个时间段只能在教室$c_i$上课,另一个上这门课的教室在$d_i$。现在你最多可以进行m次申请,对于第i个时间段的申请如果成功,那么就能在$d_i$教室上课,但成功率为$p_i$。且教室与教室之间用e条双向道路连接,每条路有一个耗费体力的值。问申请哪几门课程可以使因在教室间移动耗费的体力值的总和的期望值最小。

解题思路:这是一道期望dp问题。对于每一时间段(第一时间段除外),我们可以分为这么几种情况。

①该时间段不申请:

1.上时间段申请 成功/失败

2.上时间段不申请

②该时间段申请:

1.该时间段申请 成功/失败 and 上时间段申请 成功/失败

2.上时间段不申请

设f[i][j][0], f[i][j][1]表示当前在第i个时间段,申请了j个教室,0表示申请不通过,1表示申请通过,最小耗费体力的期望值。

dis[i][j]表示教室i到教室j的最短路。

综合以上几点情况,可得以下状态转移方程:

$f(i,j,0)=min(f(i-1,j,0)+dis(c_{i-1},c_i),f(i-1,j,1)+dis(d_{i-1}+c_i)*p_{i-1}+dis(c_{i-1},c_i)*(1-p_{i-1}))$
$f(i,j,1)=min(f(i-1,j-1,0)+dis(c_{i-1},d_i)*p_i+dis(c_{i-1},c_i)*(1-p_i),f(i-1,j-1,1)+dis(d_{i-1},d_i)*p_{i-1}*p_i+dis(d_{i-1},c_i)*p_{i-1}*(1-p_i)+dis(c_{i-1},d_i)*(1-p_{i-1})*p_i+dis(c_{i-1},c_i)*(1-p_{i-1})*(1-p_i))$

dis用floyd求出,注意dis[i,i]=0

那么时间复杂度为$O(v^3+nm)$。空间复杂度为$O(v^2+nm)$,可以用滚动数组优化为$O(v^2+m)$。

C++ Code:

#include<cstdio>
#include<cstring>
using namespace std;
int n,m,v,e,c[2002],d[2002],dis[302][302];
double p[2002],f[2][2002][2];
template<typename T>
inline T min(T a,T b){return(a<b)?a:b;}
int main(){
	scanf("%d%d%d%d",&n,&m,&v,&e);
	memset(dis,0x3f,sizeof dis);
	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",&p[i]);
	while(e--){
		int u,v,t;
		scanf("%d%d%d",&u,&v,&t);
		dis[u][v]=dis[v][u]=min(dis[u][v],t);
	}
	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)
	if(i!=k)
	for(int j=1;j<=v;++j)
	if(i!=j&&j!=k)
	dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
	memset(f,0x7f,sizeof f);
	f[1][0][0]=f[1][1][1]=0;
	for(int i=2;i<=n;++i){
		memset(f[i&1],0x7f,sizeof f[i&1]);
		f[i&1][0][0]=f[i&1^1][0][0]+dis[c[i-1]][c[i]];
		for(int j=1;j<=i&&j<=m;++j){
			f[i&1][j][0]=min(f[i&1^1][j][0]+dis[c[i-1]][c[i]],
			f[i&1^1][j][1]+dis[d[i-1]][c[i]]*p[i-1]+dis[c[i-1]][c[i]]*(1-p[i-1]));
			f[i&1][j][1]=min(f[i&1^1][j-1][0]+dis[c[i-1]][d[i]]*p[i]+dis[c[i-1]][c[i]]*(1-p[i]),
			f[i&1^1][j-1][1]+dis[d[i-1]][d[i]]*p[i-1]*p[i]+dis[d[i-1]][c[i]]*p[i-1]*(1-p[i])+
			dis[c[i-1]][d[i]]*(1-p[i-1])*p[i]+dis[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i]));
		}
	}
	double ans=f[n&1][0][0];
	for(int i=1;i<=m;++i){
		ans=min(ans,f[n&1][i][0]);
		ans=min(ans,f[n&1][i][1]);
	}
	printf("%.2f\n",ans);
	return 0;
}

 

以上是关于[NOIP2016提高组]换教室的主要内容,如果未能解决你的问题,请参考以下文章

P1850 [NOIP2016 提高组] 换教室

NOIP2016提高组day1?换教室

NOIP2016提高组换教室

NOIP2016提高组 Day1 T3 换教室

洛谷 P1850 换教室(NOIp2016提高组D1T3)

BZOJ P4720[Noip2016]换教室____solution