紫书动态规划刷题记录

UVa1025 A Spy in Metro

这一道题不会就是传说中的神题目吧qwq
  虽然说这道题目确实有点好搞,我这种小白都能做出来qwq
这道题目状态确实不是特别难想,因为是线性序列,所以直接定义d(i,j)为在时间点 i 的情况下,走到 j 这个站点所需要的最小时间。那么下一阶段会有两个选择,一个是继续在这个车站待一阵子,或者有车就走。
  值得注意的是有一些细节必须弄清楚,即如何在输入的时候将时间点处理好,我是这样处理的:

for(int i=1;i<=n-1;i++){
			scanf("%d",&t[i]);
			used_t[i]=used_t[i-1]+t[i];//used_t数组表示从1到i车站总共用			  的时间,用前缀和的思想来进行处理
		}
		int st0,st1;
		scanf("%d",&st0);
		for(int i=1;i<=st0;i++){
			scanf("%d",&tr[i]);
			has_train[tr[i]][1][0]=1;
			for(int j=1;j<=n-1;j++){
				has_train[tr[i]+used_t[j]][j+1][0]=1;
				//将每一个站点的时间信息处理
			}
		}
		scanf("%d",&st1);
		for(int i=1;i<=st1;i++){
			scanf("%d",&rtr[i]);
			has_train[rtr[i]][n][1]=1;
			for(int j=n-1;j>=1;j--){
				has_train[rtr[i]+used_t[n-1]-used_t[j-1]][j][1]=1;
				//注意的就是这个情况,虽说不算特别难,但还是有一点小坑
			}
		}

P.S
有时候判断自己的预处理对不对可以在这里提前输出哦,没必要写完再输出。
那么总程序就是:

#include<bits/stdc++.h>
#define maxn 1000

using namespace std;
int n,T;
int t[maxn];
int used_t[maxn];
int tr[maxn],rtr[maxn];
bool has_train[maxn][maxn][2];
const int INF=1e9;
int dp[maxn][maxn];
int main(){
	int kase=0;
	while(scanf("%d",&n)==1&&n){
		scanf("%d",&T);
		memset(used_t,0,sizeof(used_t));
		memset(t,0,sizeof(t));
		memset(has_train,0,sizeof(has_train));
		memset(tr,0,sizeof(tr));
		memset(rtr,0,sizeof(rtr));
		memset(dp,0,sizeof(dp));
		//初始化一大堆数组,以免失误
		for(int i=1;i<=n-1;i++){
			scanf("%d",&t[i]);
			used_t[i]=used_t[i-1]+t[i];
		}
		int st0,st1;
		scanf("%d",&st0);
		for(int i=1;i<=st0;i++){
			scanf("%d",&tr[i]);
			has_train[tr[i]][1][0]=1;
			for(int j=1;j<=n-1;j++){
				has_train[tr[i]+used_t[j]][j+1][0]=1;
			}
		}
		scanf("%d",&st1);
		for(int i=1;i<=st1;i++){
			scanf("%d",&rtr[i]);
			has_train[rtr[i]][n][1]=1;
			for(int j=n-1;j>=1;j--){
				has_train[rtr[i]+used_t[n-1]-used_t[j-1]][j][1]=1;
			}
		}
		for(int i=1;i<=n-1;i++)dp[T][i]=INF;
		dp[T][n]=0;
		for(int i=T-1;i>=0;i--){
			for(int j=1;j<=n;j++){
				dp[i][j]=dp[i+1][j]+1;
				if(j<n&&has_train[i][j][0]&&i+t[j]<=T){
					dp[i][j]=min(dp[i][j],dp[i+t[j]][j+1]);
				}
				if(j>1&&has_train[i][j][1]&&i+t[j-1]<=T){
					dp[i][j]=min(dp[i][j],dp[i+t[j-1]][j-1]);
				}
			}
		}
		cout<<"Case Number "<<++kase<<": ";
		if(dp[0][1]>=INF)cout<<"impossible"<<endl;
		else cout<<dp[0][1]<<endl;;
	}
}

还是太菜了,这道题目本来应该几个月前就应该会的qwq
警醒zz的自己

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值