动态规划训练19、最短路 [Help Jimmy POJ - 1661 ]

Help Jimmy

  POJ - 1661 

题意:大致是一个人从某个点开始下落,下落的速度是1m/s,然后在平台上的时候可以左右移动,移动的速度也是1m/s,但是这里有一个限制,就是说每次下落的距离不能超过一个给定的数值。问你从起始点下落到地板最少需要多少s。

题解,这道题我看到的时候第一感觉是最短路,建图方法就是对于每一个平台的两个端点(编号为2*i+1和2*i+2),考虑这个从端点所能下落到的下一个平台的两个端点,比如,根据上一个平台的某个端点到下一个最近的平台的两个端点所需要的时间来建立边(边权就是耗费的时间)

最后别忘了从起点开始的建边以及端点到地板的建边!

动态规划的做法等会了再补上

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
#define int long long 
const int MAXN = 2005;
const int INF = 1e18;
int N,X,Y,MAX;
//int G[MAXN][MAXN];
//vector<int> G[MAXN];
int head[MAXN];
struct edge{
	int v;
	int next;
	int cost;
}Es[MAXN<<1];
int d[MAXN];
int cnt;
typedef pair<int,int> P;
struct node{
	int x1,x2,h;
	friend bool operator<(node n1,node n2){
		return n1.h > n2.h;
	}
};
node ns[MAXN];
void dijkstra(int x){
	for(int i = 0;i <= MAXN;i++)
		d[i] = INF;
	d[x] = 0;
	priority_queue<P,vector<P>,greater<P> > que;
	que.push(P(0,x));
	while(!que.empty()){
		P p = que.top();que.pop();
		int dis = p.first;
		int v = p.second;
		if(d[v] < dis) continue;
		//for(int i = 0;i < 2*N+2;i++){
		for(int e = head[v];e!= -1;e = Es[e].next){
			int cost = Es[e].cost;
			int i = Es[e].v;
			if(cost + d[v] < d[i]){
				d[i] = d[v] + cost;
				que.push(P(d[i],i));
			}
		}
	}
}
inline void add_edge(int i,int j,int cost){
	//G[i][j] = cost;
	Es[cnt].v = j;
	Es[cnt].cost = cost;
	Es[cnt].next = head[i];
	head[i] = cnt++;
}
void init(){
	cnt = 0;
	memset(head,-1,sizeof(head));
}
main(){
	int t;
	scanf("%lld",&t);
	while(t--){
		init();
		scanf("%lld%lld%lld%lld",&N,&X,&Y,&MAX);
		for(int i = 0;i < N;i++){
			int x1,x2,h;
			scanf("%lld%lld%lld",&x1,&x2,&h);
			ns[i].x1 = x1;
			ns[i].x2 = x2;
			ns[i].h = h;
		}
		sort(ns,ns+N);
		//create graph
		for(int i = 0;i < N;i++){
			int l = 0,r = 0;
			int f = 1;
			for(int j = i + 1;j < N;j++){
				if(ns[i].h - ns[j].h > MAX){
					f = 0;
					break;
				}
				if(!l && ns[i].x1 >= ns[j].x1 && ns[i].x1 <= ns[j].x2){
					l = 1;
					add_edge(2*i+1,2*j+1,ns[i].h - ns[j].h + ns[i].x1 - ns[j].x1);
					add_edge(2*i+1,2*j+2 ,ns[i].h - ns[j].h + ns[j].x2 - ns[i].x1);
				}
				if(!r && ns[i].x2 >= ns[j].x1 && ns[i].x2 <= ns[j].x2){
					r = 1;
					add_edge(2*i+2,2*j+1,ns[i].h - ns[j].h + ns[i].x2 - ns[j].x1);
					add_edge(2*i+2,2*j+2,ns[i].h - ns[j].h + ns[j].x2 - ns[i].x2);
				}
				if(r && l) break;
			}
			if(!f)continue; 
			if(!l && ns[i].h <= MAX){
				add_edge(2*i+1,2*N+1,ns[i].h);
			}
			if(!r && ns[i].h <= MAX){
				add_edge(2*i+2,2*N+1,ns[i].h);
			}
		}
		int f = 0;
		for(int i = 0;i < N;i++){
			if(X > ns[i].x1 && X < ns[i].x2 && Y >= ns[i].h && Y - ns[i].h <= MAX){
				add_edge(0,2*i+1,Y - ns[i].h + X - ns[i].x1);
				add_edge(0,2*i+2,Y - ns[i].h + ns[i].x2 - X);
				f = 1;
				break;
			}
		}
		if(!f){
			if(Y <= MAX){
				add_edge(0,2*N+1,Y);
			}
		}
		dijkstra(0);
		cout<<d[2*N+1]<<endl;
	}
}
 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值