UVa 1025 (DAG 上的动态规划,有固定终点的最短时间,逆推法)

本文介绍了一种解决特定场景下最短等待时间问题的动态规划算法,通过构建时间与站点坐标图,利用逆推法求解从起点到终点的最小等待时间。

题目链接

题意:  某城市的地铁是线性的,有n(2≤n≤50)个车站,从左到右的编号为1~N.有M1辆列车从第一站开始往右开,还有M2辆列车从第n站开始往左开。在时刻0,Mario从第1站出发,目的是在时刻T(0≤T≤200)会见车站n的一个间谍。在车站等车容易被抓,所以她决定尽量躲在开动的火车上,让在车站等待的总时间尽量短。列车靠站停车时间忽略不计,且Mario身手敏捷,即使两辆方向不同的列车在同一时间靠站,Mario也能完成换乘。求最少等待时间


思路: 这是一道给出 固定终点的求最最短等待时间的题,1,首先时间是单向流逝的,是一个天然的序,2.可以把时间t,站 n,看做一个点,建图,下面代码中has[i][j][0] 是代表当时间为i,站为j时,看看是否有向右的车,has[][][1]  是看看是否有向左的车;3 因时间是一个天然的序,dp[i][j] 代表 当时间为i,站为j 时,要到达 时间为t,站为n,需要等待的最短时间;则采用逆推法,dp[t][n] 一定为0吧,逆推法一只到dp[0][1];(在刘汝佳老师的紫书上,讲的DAG 上的动态规划上 的 硬币问题也可以采用逆推法,把终点设为s,我的收藏中有终点为0的)

在这个状态转移的过程中,无非有三种决策

1 没有车,等上一分钟,看看下一分钟有没有车;

2 若有向右的车,搭载向右的车;

3 若有向左的车,搭载向左的车;

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 210
#define INF 0x3f3f3f3f

int time[60],has[Max][60][2];
int dp[Max][60];  // dp[i][j] 时间为i分,j站,到达时间t,n站的需要等的最小时间; 
int n,t,M1,M2;

void init()
{
	memset(has,0,sizeof(has));
	memset(dp,INF,sizeof(dp));
}

int main()
{
	int i,j,k,num=1;
	while(~scanf("%d",&n)&&n)
	{
		init();
		scanf("%d",&t);
		for(i=1;i<n;i++)
			scanf("%d",&time[i]);
		scanf("%d",&M1);
		for(i=1; i<=M1; i++)     //建图,时间t,站n,为一个坐标(t,n),has 数组是看看有没有开往相邻坐标的车,相邻坐标由站和站于站之间的时间决定; 
		{							//has[i][j][0] ,表示看看有没有开往右边的车,has[i][j][1],看看有没有开往左边的车; 
			scanf("%d",&k);
			for(j=1;j<=n;j++)
			{
				if(j==1) has[k][j][0] = 1;
				else 
				{
					k = k + time[j-1];
					if(k>t) continue;
					has[k][j][0] = 1;
				}
			}
		}
		scanf("%d",&M2);
		for(i = 1; i <= M2; i ++)
		{
			scanf("%d",&k);
			for(j = n;j >=1;j --)
			{
				if(j==n) has[k][j][1] = 1;
				else
				{
					k = k + time[j];
					if(k>t) continue;
					has[k][j][1] = 1;
				}
			}
		}
		dp[t][n] = 0; // 逆推法,因为当时间为t,n站,到达时间为t,n站,需要的最小时间一定是0;
					  // 随的时间减少,那么到时间t,n站的需要等的时间,会增加,也可能不变;
					  	//状态转移;  
		for(i = t - 1; i >= 0; i--)
		{
			for(j = 1 ; j <= n; j++)    
			{
				dp[i][j] = dp[i+1][j] + 1; //等一分钟;如果等一分钟,就到了i+1分钟,j站,从i+1分钟,j站这个状态, 
				if(j<n&&has[i][j][0]&&i+time[j]<=t)  //需要看i+1分,j站时,需要等车时间,在这个时间上再加1,就是dp[i][j],等一分钟的时间;
				{
					dp[i][j] = min(dp[i][j],dp[i+time[j]][j+1]); // 坐车时间不算,dp 数组中存的时间为在每一站等车的时间; 
				}
				if(j>1&&has[i][j][1]&&i+time[j-1]<=t)
				{
					dp[i][j] = min(dp[i][j],dp[i+time[j-1]][j-1]); 
				}
			}
		}
		if(dp[0][1]>=INF)
			 printf("Case Number %d: impossible\n",num++);
		else printf("Case Number %d: %d\n",num++,dp[0][1]);
	}
	return 0;	
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值