Codeforces 596D 区间DP

原创 2015年11月19日 00:12:35

题目链接:

题意:

  有n棵树排成一排,高度都为h.

  主人公要去砍树,每次等概率地随机选择没倒的树中最左边的树或者最右边的树把它砍倒.每棵树被砍到后,有p的概率会往左边倒,(1-p)的概率往右边倒.

  树倒下后如果压到别的树,即如果那棵树倒下的方向上距离不到h的地方还有一棵树,,那么那棵树也会朝和这个树相同的方向倒下.

  问最后所有的树都被砍完后覆盖的地面的长度的期望.



分析:

  由于树的数量n只有1000,所以O(n^2)的方法是可行的.很自然就能想到区间DP.

  设DP(l,r,s1,s2)为砍掉第l棵树到第r棵树之间的所有树,并且第l-1棵树的状态s1,第r+1棵树的状态是s2,此时覆盖地面的长度的期望.其中,s1和s2只有0和1两种取值,0表示向左倒,1表示向右倒.

  那么最后的结果即DP(1,n,0,1),第0棵树和第n+1棵树要设的足够远以免对结果产生影响.

  状态的转移慢慢推就好.

  DP(l,r,s1,s2)的结果可以从DP(l+1,r,0,s2),DP(l+1,r,1,s2),DP(l,r-1,s1,0),DP(l,r-1,s1,1)四种情况推导出来.

  需要注意的是边界条件.

  具体还是看代码吧.


#include <bits/stdc++.h>
using namespace std;
const int maxn=2005;
int h;
double p;
int a[maxn];
double dp[maxn][maxn][2][2];
double DW(int l,int r,int sl,int sr)
{
	if (dp[l][r][sl][sr]) return dp[l][r][sl][sr];
	if (l==r) 
	{
		if (sl&&a[l-1]+h>a[l]) 
		{
			if (sr) return dp[l][r][sl][sr]=min(h,a[l+1]-a[l]);
			else return dp[l][r][sl][sr]=min(h,max(0,a[r+1]-a[r]-h));
		}
		else if (!sr&&a[r+1]-h<a[r]) 
		{
			if (sl) return dp[l][r][sl][sr]=min(h,max(a[l]-a[l-1]-h,0));
			else return dp[l][r][sl][sr]=min(h,a[l]-a[l-1]);
		}
		double ans=0;
		if (sl) ans+=p*min(h,max(a[l]-a[l-1]-h,0));
		else ans+=p*min(h,a[l]-a[l-1]);
		if (sr) ans+=(1-p)*min(h,a[r+1]-a[r]);
		else ans+=(1-p)*min(h,max(0,a[r+1]-a[r]-h));
		return dp[l][r][sl][sr]=ans;
	}
	if (sl&&a[l-1]+h>a[l])       return dp[l][r][sl][sr]=DW(l+1,r,1,sr)+min(h,a[l+1]-a[l]);
	else if (!sr&&a[r+1]-h<a[r]) return dp[l][r][sl][sr]=DW(l,r-1,sl,0)+min(h,a[r]-a[r-1]);
	double ans=0;
	ans+=0.5*(1-p)*(DW(l+1,r,1,sr)+min(h,a[l+1]-a[l]));
	ans+=0.5*p    *(DW(l,r-1,sl,0)+min(h,a[r]-a[r-1]));
	if (sl) ans+=0.5*p*(DW(l+1,r,0,sr)+min(h,max(0,a[l]-a[l-1]-h)));
	else    ans+=0.5*p*(DW(l+1,r,0,sr)+min(h,a[l]-a[l-1]));
	if (sr) ans+=0.5*(1-p)*(DW(l,r-1,sl,1)+min(h,a[r+1]-a[r]));
	else    ans+=0.5*(1-p)*(DW(l,r-1,sl,1)+min(h,max(0,a[r+1]-a[r]-h)));
	return dp[l][r][sl][sr]=ans;
}
int main()
{
	int n;
	while (~scanf("%d%d%lf",&n,&h,&p))
	{
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		memset(dp,0,sizeof(dp));
		sort(a+1,a+n+1);
		a[0]=a[1]-h;
		a[n+1]=a[n]+h;
		printf("%.12lf\n",DW(1,n,0,1));
	}
	return 0;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

区间DP入门之 石子归并问题

题目描述:有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最...
  • wuxuanyi27
  • wuxuanyi27
  • 2016年04月21日 21:40
  • 850

Codeforces Round #406 (Div. 2):C. Berzerk(记忆化搜索解决博弈问题)

C. Berzerk time limit per test 4 seconds memory limit per test 256 megabytes input standard in...
  • Jaihk662
  • Jaihk662
  • 2017年03月24日 15:23
  • 798

动态规划学习系列——区间DP(一)

学习一个算法,还是从题目开始比较好,我们就从一道经典例题开始: wikioi 1048 石子归并 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相...
  • fuyukai
  • fuyukai
  • 2015年02月13日 17:13
  • 809

【打CF,学算法——五星级】CodeForces 478D (dp计数)

【CF简介】 提交链接:CF 478D 题面: D. Red-Green Towers time limit per test 2 seconds ...
  • David_Jett
  • David_Jett
  • 2016年07月12日 11:11
  • 504

区间DP 入门经典三道题

NYOJ 737:http://acm.nyist.net/JudgeOnline/problem.php?pid=737 代码:#include #include #include #def...
  • SolarDomo
  • SolarDomo
  • 2016年08月15日 14:17
  • 480

概率dp入门的简单题(hdu 4405,牡丹江,codeforces)

最近学习了一下概率dp,感觉没有想象中的那么难。主要还是状态的转移方程的构建。 对于”求概率正推,求期望反推“这句话有了初步的理解。期望的意思是说你现在处在一个状态,还需要几步到达最终状态,这是一个期...
  • NK_test
  • NK_test
  • 2015年05月07日 23:58
  • 723

poj3264 线段树维护最大值最小值

用线段树来维护区间的最大值最小值   建好线段树,就可以针对查询来查出最大值最小值  从而求出其差值 #include #include #include #include ...
  • jk13171217
  • jk13171217
  • 2015年08月04日 16:35
  • 247

dp 计数问题 复杂整数划分 区间dp

百练的题目 : 让我对dp有了新体会 这是记忆化搜索写法 省了很多时间 并且状态转移的方式符合我们的认知  这个通过递推很难发现关系 但是讲区间搜索一下分解的话就可以计数了 并且在不影响结果的前提下自...
  • qq_34271269
  • qq_34271269
  • 2016年07月19日 21:32
  • 349

Codeforces-785E-Anton and Permutation(分块区间查询,动态查询[l,r]内小于某个值的元素个数)

题目链接:Codeforces-785E-Anton and Permutation当交换a[l]和a[r]时。讨论区间为(l,r),那么ans=ans+区间内比a[r]小的个数−区间内比a[l]小的...
  • jinglinxiao
  • jinglinxiao
  • 2017年03月26日 18:54
  • 393

Codeforces 724E 最大流=最小割+dp求最小割

题意: 有n个城市,每个城市有p【i】的东西,可以在那个城市卖c【i】的东西,两两城市可以进行一次c的运送,只能从小的编号的往大的编号运。 问最多能卖多少货物。 思路: 最大流:建图,s到n个...
  • naipp
  • naipp
  • 2016年10月10日 17:49
  • 640
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Codeforces 596D 区间DP
举报原因:
原因补充:

(最多只允许输入30个字)