1021 - 期望dp - 花园(SCOI2017 DAY2 T1)

题目描述

小 A 的花园的长和宽分别是 L,H 。小 A 喜欢在花园里做游戏。每次做游戏的时候,他都先把花园均匀分割成 L×H 个小方块,每个方块的长和宽都是 1 。然后,小 A 会从花园的西北角的小方块出发,按照一定的规则移动,在到达花园东南角的小方块时结束游戏。每次行动时,他都会移动到当前所在的小方块的东面或南面相邻的小方块上。如果小 A 当前在从北向南数第 i 块,从西向东数第 j 块小方块上,他向东移动的概率是 Pij ,向南移动的概率则是 1-Pij 。

在花园里做游戏常常会弄脏衣服,花园的每个小方块内都有一定的不干净度,用 Dij 表示。而一次游戏结束后,小 A 总的不干净度就是他经过的所有格子中不干净度之和(起点和终点的不干净度也计算在内)。

小 B 因为小 A 经常把衣服弄脏感到苦恼,他可能会决定在小 A 做游戏前对花园进行一次打扫。小 B 在打扫花园时,会从花园的西北角的小方块出发,每次移动到当前所在的小方块的东面或南面相邻的小方块上,在到达花园的东南角时结束打扫,他经过的所有的格子的不干净度都会变为 0 。现在,小 B 想知道,在他选择了最优的打扫策略的情况下,小 A 做完游戏后总不干净度之和是多少?

输入格式

第一行输入两个空格隔开的正整数 L、H。
第二行一个整数 k,值为 0 或 1 ,k=0 表示小B不会打扫花园,k=1 表示小B会在游戏开始前打扫花园。

接下来 L 行,每行有 H 个自然数,第 i 行第 j 个数表示从北往南数第 i 个,从西往东数第 j 个小方块的不干净度 Dij 。

接下来 L 行,每行有 H 个实数,第 i 行第 j 个数表示从北往南数第 i 个,从西往东数第 j 个小方块的参数 Pij 。

输出格式

输出一个整数,表示问题的答案,四舍五入保留到整数。

样例数据 1

输入 
3 3
0
200 100 100
200 100 300
100 200 300
0.5 0.5 0.0
1.0 1.0 1.0
输出
1000

样例数据 2

输入 
3 3
1
200 100 100
200 100 300
100 200 300
0.2 0.8 0.0
0.8 0.3 0.0
1.0 1.0 1.0
输出
161

备注

【数据范围】
你的答案必须和标准输出完全一致才能得分,为确保精度误差在一定范围内的答案能被接受,

保证准确答案的小数点后第 1 位数字不是 4 或 5 。
0≤Dij≤10000 ;
0≤Pij≤1 最多包含两位小数 ;
PLi=1 (1≤i<H) 且 PiH=0 (1≤i<L),即走到棋盘外的概率为 0 ,最终必然会到达东南角结束。PLH=1,但到达这里时旅途已经结束了,这个数没有意义;
1≤L,H≤1000 。
在这里插入图片描述
特殊性质:0 表示没有特殊性质,1 表示除了最后一行和最后一列的小方块外,所有的小方块的参数都为 0.5 。

分析

好有意思的一道题,居然没读懂题意????
问“做完游戏后总不干净度之和”
其实就是问“所有可能的方案下不干净度之和”
由于这句话“他向东移动的概率是 Pij ,向南移动的概率则是 1-Pij ”我们就知道最后要求的是和的期望
期望的线性性告诉我们:和的期望可以拆成每一个点的期望的和
对于这道题每个点的期望就是指:走到这个点的概率乘以其不干净度
最后累加起来即可

但我们好像忘了小B这号人物了,假设他不打扫,那就是上面所说
但他如果打扫了的话,就应该在之前的基础上减去一个值
减多少呢?
由于小B是按照最优的打扫策略,就是说他走过的点的不干净度之和最大,我们就在维护每一个点的期望 的同时,记录下走到当前位置的不干净度最大是多少

单向膜拜ldx大佬(反正他也看不见……)

代码

#include<bits/stdc++.h>
#define in read()
#define N 1005
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return f==1?res:-res;
} 
int l,h,k;
double d[N][N],p[N][N],g[N][N],f[N][N];
//f[i][j]-->(i,j)'s gailve
//g[i][j]-->for B to clean
int main(){
  	l=in;h=in;k=in;
  	int i,j;
  	for(i=1;i<=l;++i)
  		for(j=1;j<=h;++j)
  			d[i][j]=in;
  	for(i=1;i<=l;++i)
  		for(j=1;j<=h;++j)
  			scanf("%lf",&p[i][j]);
  	double sum=d[1][1];f[1][1]=1;g[1][1]=d[1][1];
  	for(i=1;i<=l;++i)
  		for(j=1;j<=h;++j){
  			if(i==1&&j==1) continue;
  			f[i][j]=(f[i-1][j]*(1-p[i-1][j])+f[i][j-1]*p[i][j-1]);
  			sum+=(g[i][j]=f[i][j]*d[i][j]);
  			g[i][j]+=max(g[i-1][j],g[i][j-1]);
  		}
  	printf("%.0lf",sum-k*g[l][h]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值