小单刷题笔记之画廊(DP)


 

昨天做的一道蓝桥杯国赛真题,一开始没想到DP的状态转移,暴力debug了一晚上,跑了30分,今天研究了一下DP解法,从他给的样例入手先画个图。

测试样例应该就是这么走的,有可能走斜线,有可能走直线,因为两边的画是错开放的,所以从左到右一定是斜线。根据勾股定理可以写个函数来求。那状态怎么定义呢?dp[i][j]表示左边i个画完成右边j个画完成的最短距离,但是就拿dp[1][1]来说,左右各完成一个,他此时有可能在左边,也有可能在右边,我们没办法确认他在左边还是右边,缺一种状态,所以多加一种状态,0表示左边,1表示右边,用dp[i][j][0]和dp[i][j][1]来表示状态

这样其实转移方程并不难想,应该是——

                dp[i][j][0]=min(dp[i][j][0],min(dp[i-1][j][0]+l[i]-l[i-1],dp[i-1][j][1]+slash(l[i],r[j],w)));

dp[i-1][j][0]表示:左边i-1个完成了,右边j个完成了,此时在左边,那么它到达dp[i][j][0]的方式应该是走直线,就加上两点之间的直线距离。

dp[i-1][j][1]表示:左边i-1个完成了,右边j个完成了,此时在右边,那么它到达dp[i][j][0]的方式应该是走斜线,就加上斜线的距离。

 初始化:初始确定的状态应该就两种,第一种是dp[1][0][0],因为只完成左边第一幅画此时一定在左边,不可能在右边。第二种就是dp[0][1][1],因为只完成右边第一幅画一定在右边。

然后注意要把dp数组用memset全部制成极大值,保证不存在的状态例如:dp[0][3][0]这种东西不会影响到状态转移。(左边没有完成一幅画不可能在左边)

所以状态转移的时候也要多套一层min,不然初始的状态会受影响(可能被不存在的状态更新成不存在的值);

附上memset的妙用:


#include <string.h> 
int a[100];
memset(map,0,sizeof(map)); //全为0
memset(map,-1,sizeof(map)); //全为-1
memset(map,127,sizeof(map)); //全为无穷大 
memset(map,128,sizeof(map)); //全为无穷小

AC代码如下:

#include<bits\stdc++.h>
using namespace std;
double slash(double x,double y,double w){
	return sqrt((x-y)*(x-y)+w*w);
}
double l[505],r[505];
double dp[505][505][2];
int main(){
	int L,R;
	double d,w;
	cin>>L>>R>>d>>w;
	memset(dp,127,sizeof(dp));
	for(int i=1;i<=L;++i)cin>>l[i];
	for(int i=1;i<=R;++i)cin>>r[i];
	dp[1][0][0]=slash(l[1],0,w/2.00);
	dp[0][1][1]=slash(r[1],0,w/2.00);
	for(int i=0;i<=L;i++){
		for(int j=0;j<=R;j++){
if(i)dp[i][j][0]=min(dp[i][j][0],min(dp[i-1][j][0]+l[i]-l[i-1],dp[i-1][j][1]+slash(l[i],r[j],w)));
if(j)dp[i][j][1]=min(dp[i][j][1],min(dp[i][j-1][1]+r[j]-r[j-1],dp[i][j-1][0]+slash(l[i],r[j],w)));
		}
	}		
	double ans=min(dp[L][R][0]+slash(d,l[L],w/2.00),dp[L][R][1]+slash(d,r[R],w/2.00));
	printf("%.2f",ans);
	
	
	return 0;
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值