【NOIP 2016 提高组】换教室

传送门


problem

在这里插入图片描述
数据范围: 1 ≤ n ≤ 2000 1≤n≤2000 1n2000 0 ≤ m ≤ 2000 0 \leq m \leq 2000 0m2000 1 ≤ v ≤ 300 1 \leq v \leq 300 1v300 0 ≤ e ≤ 90000 0 \leq e \leq 90000 0e90000


solution

f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1] 表示在前 i i i 个时间段申请换了 j j j 次课,且第 i i i 个时间段不换课 / / /换课的最小期望值。

下面的 d i s [ i ] [ j ] dis[i][j] dis[i][j] 表示 i i i j j j 的最短路,由于点比较少,可以直接 floyd 求。

当第 i i i 节课不申请换的时候(即 f ( i , j , 0 ) f(i,j,0) f(i,j,0)

如果第 i − 1 i-1 i1 节课不申请换,贡献 d i s [ c i − 1 ] [ c i ] + f [ i − 1 ] [ j ] [ 0 ] dis[c_{i-1}][c_i]+f[i-1][j][0] dis[ci1][ci]+f[i1][j][0]

如果第 i − 1 i-1 i1 节课申请换,那有两种情况:

  • 换课成功,贡献 k i − 1 × ( d i s [ d i − 1 ] [ c i ] + f [ i − 1 ] [ j ] [ 1 ] ) k_{i-1}\times(dis[d_{i-1}][c_i]+f[i-1][j][1]) ki1×(dis[di1][ci]+f[i1][j][1])
  • 换课失败,贡献 ( 1 − k i − 1 ) × ( d i s [ c i − 1 ] [ c i ] + f [ i − 1 ] [ j ] [ 1 ] ) (1-k_{i-1})\times(dis[c_{i-1}][c_i]+f[i-1][j][1]) (1ki1)×(dis[ci1][ci]+f[i1][j][1])

取个 min ⁡ \min min 即可。

当第 i i i 节课申请换的时候(即 f ( i , j , 1 ) f(i,j,1) f(i,j,1)

如果第 i − 1 i-1 i1 节课不申请换:

  • i i i 节换课成功,贡献 k i × ( d i s [ c i − 1 ] [ d i ] + f [ i − 1 ] [ j − 1 ] [ 0 ] ) k_i\times (dis[c_{i-1}][d_i]+f[i-1][j-1][0]) ki×(dis[ci1][di]+f[i1][j1][0])
  • i i i 节换课失败,贡献 ( 1 − k i ) × ( d i s [ c i − 1 ] [ c i ] + f [ i − 1 ] [ j − 1 ] [ 0 ] ) (1-k_i)\times (dis[c_{i-1}][c_i]+f[i-1][j-1][0]) (1ki)×(dis[ci1][ci]+f[i1][j1][0])

如果第 i − 1 i-1 i1 节课申请换:

  • i i i 节换课成功,第 i − 1 i-1 i1 节换课成功,贡献 k i × k i − 1 × ( d i s [ d i − 1 ] [ d i ] + f [ i − 1 ] [ j − 1 ] [ 1 ] ) k_i\times k_{i-1}\times (dis[d_{i-1}][d_i]+f[i-1][j-1][1]) ki×ki1×(dis[di1][di]+f[i1][j1][1])
  • i i i 节换课成功,第 i − 1 i-1 i1 节换课失败,贡献 k i × ( 1 − k i − 1 ) × ( d i s [ c i − 1 ] [ d i ] + f [ i − 1 ] [ j − 1 ] [ 1 ] ) k_i\times (1-k_{i-1})\times (dis[c_{i-1}][d_i]+f[i-1][j-1][1]) ki×(1ki1)×(dis[ci1][di]+f[i1][j1][1])
  • i i i 节换课失败,第 i − 1 i-1 i1 节换课成功,贡献 ( 1 − k i ) × k i − 1 × ( d i s [ d i − 1 ] [ c i ] + f [ i − 1 ] [ j − 1 ] [ 1 ] ) (1-k_i)\times k_{i-1}\times (dis[d_{i-1}][c_i]+f[i-1][j-1][1]) (1ki)×ki1×(dis[di1][ci]+f[i1][j1][1])
  • i i i 节换课失败,第 i − 1 i-1 i1 节换课失败,贡献 ( 1 − k i ) × ( 1 − k i − 1 ) × ( d i s [ c i − 1 ] [ c i ] + f [ i − 1 ] [ j − 1 ] [ 1 ] ) (1-k_i)\times (1-k_{i-1})\times (dis[c_{i-1}][c_i]+f[i-1][j-1][1]) (1ki)×(1ki1)×(dis[ci1][ci]+f[i1][j1][1])

看起来比较麻烦,但是思维很简单。

时间复杂度 O ( v 3 + n m ) O(v^3+nm) O(v3+nm)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2005
using namespace std;
int n,m,v,e;
int c[N],d[N],dis[N][N];
double K[N],f[N][N][2];
int main(){
	int x,y,z;
	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]);
	memset(dis,127/3,sizeof(dis));
	for(int i=1;i<=e;++i){
		scanf("%d%d%d",&x,&y,&z);
		dis[x][y]=dis[y][x]=min(dis[x][y],z);
	}
	for(int k=1;k<=v;++k)
		for(int i=1;i<=v;++i)
			for(int j=1;j<=v;++j)
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
	for(int i=1;i<=v;++i)  dis[i][i]=0;
	for(int i=1;i<=n;++i)
		for(int j=0;j<=m;++j)
			f[i][j][0]=f[i][j][1]=1e18;
	f[1][0][0]=f[1][1][1]=0;
	for(int i=2;i<=n;++i){
		for(int j=0;j<=m;++j){
			f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],f[i-1][j][1]+K[i-1]*dis[d[i-1]][c[i]]+(1-K[i-1])*dis[c[i-1]][c[i]]);
			if(j>0)  f[i][j][1]=min(f[i-1][j-1][0]+dis[c[i-1]][d[i]]*K[i]+dis[c[i-1]][c[i]]*(1-K[i]),f[i-1][j-1][1]+dis[d[i-1]][d[i]]*K[i-1]*K[i]+dis[c[i-1]][d[i]]*(1-K[i-1])*K[i]+dis[d[i-1]][c[i]]*K[i-1]*(1-K[i])+dis[c[i-1]][c[i]]*(1-K[i-1])*(1-K[i]));
		}
	}
	double ans=1<<30;
	for(int i=0;i<=m;++i)  ans=min(ans,min(f[n][i][0],f[n][i][1]));
	printf("%.2lf\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值