kuangbin专题十二 POJ1661 Help Jimmy

传送门:http://poj.org/problem?id=1661

思路:本来以为是dp二维x, y, 但是不可能开那么大,状态也不好规划。无奈之下看了题解。

dp[i][0]表示从左边到达i的最小花费
dp[i][1]表示从右边到达i的最小花费

然后考虑怎么转移。

例:

                   -----------------------------------         

           ----------------                  --------------------

到达最上面的木板可以从左边或右边,下面的一直递推。

状态转移方程:

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

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

也就是线段左端 + 交叉的距离 或 线段右端 + 交叉的距离

其中还有最大高度的细节处理,分为两类,①找不到并且距离之外,②找不到但距离之内

AC代码:

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
using namespace std;
#define mem(a,b) memset((a),(b),sizeof(a))
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define all(x) x.begin(),x.end()
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-5;
const ll mod = 1e9+7;
//head

int dp[1010][2];//dp[i][0]表示从左边到达i的最小花费
				//dp[i][1]表示从右边到达i的最小花费
struct node{
	int r, l, h;
}stu[1010];

bool cmp(node a, node b) {//按高度排序
	if(a.h != b.h)
		return a.h < b.h;
	return a.l < b.l;
}

bool flag;
int main(int argc, char const *argv[])
{
	int _, n, x, y, m;
	for(scanf("%d", &_);_;_--) {
		memset(dp, 0, sizeof(dp));
		scanf("%d%d%d%d", &n, &x, &y, &m);
		for(int i = 0; i < n; i++) {
			scanf("%d%d%d", &stu[i].l, &stu[i].r, &stu[i].h);
		}
		sort(stu, stu + n, cmp);
		stu[n].l = stu[n].r = x;
		stu[n].h = y;
		for(int i = 0; i < n + 1; i++) {
			flag = false;//标记
			for(int j = i - 1; j >= 0; j--) {//左
				if(stu[i].h - stu[j].h <= m && stu[i].h > stu[j].h)//保证不摔的前提
					if(stu[j].l <= stu[i].l && stu[j].r >= stu[i].l) {//可以从左边到达的条件
						dp[i][0] = stu[i].h - stu[j].h + min(dp[j][0] + stu[i].l - stu[j].l, dp[j][1] + stu[j].r - stu[i].l);
						flag = true;//标记找到
						break;//递推,找到一个就break
					}
			}
			if(stu[i].h > m && flag == false) {//如果找不到,并且木板i到达地面高度大于m  -----无穷大
				dp[i][0] = inf;
			} else if(flag == false){//找不到,但是到达地面高度 <= m
				dp[i][0] = stu[i].h;
			}
			flag = false;//同理求出右边的最小花费
			for(int j = i - 1; j >= 0; j--) {//右
				if(stu[i].h - stu[j].h <= m && stu[i].h > stu[j].h)
					if(stu[j].l <= stu[i].r && stu[j].r >= stu[i].r) {
						dp[i][1] = stu[i].h - stu[j].h + min(dp[j][0] + stu[i].r - stu[j].l, dp[j][1] + stu[j].r - stu[i].r);
						flag = true;
						break;
					}
			}
			if(stu[i].h > m && flag == false) {
				dp[i][1] = inf;
			} else if(flag == false) {
				dp[i][1] = stu[i].h;
			}
		}
		printf("%d\n", min(dp[n][0], dp[n][1]));//到达木板n的最小花费
	}
	return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值