UVA1025——A Spy in the Metro【dp】

题目链接:https://cn.vjudge.net/problem/UVA-1025

题目大意:Mario从第1站出发,目的是在时刻T会见车站 n n n 的一个间谍。由于在车站等待容易被抓,所以应尽量躲在开动的火车上,即在车站等待的时间最短,且Mario十分敏捷,及时两辆方向不同的列车在同一时间停靠,她也能完成换乘。
输入的第1行为 n ( 2 ≤ n ≤ 50 ) n(2 \le n \le 50) n(2n50) ,第2行为 T ( 0 ≤ T ≤ 200 ) T(0 \le T \le 200) T(0T200) ,第3行有 n − 1 n-1 n1 个整数 t 1 , t 2 , … , t n − 1 t_1,t_2,\dots,t_{n-1} t1,t2,,tn1 ( 1 ≤ t i ≤ 70 ) (1 \le t_i \le 70) (1ti70) ,其中 t i t_i ti 表示地铁从车站 i i i 到车站 i + 1 i+1 i+1 的行驶时间(两个方向一样)。第4行为 M 1 ( 1 ≤ M 1 ≤ 50 ) M1(1 \le M1 \le 50) M1(1M150),即从第1站出发向右开的列车数目。第5行包含 M 1 M1 M1 个整数 d 1 , d 2 , … , d M 1 ( 0 ≤ d i ≤ 250 , d i &lt; d i + 1 ) d_1,d_2,\dots,d_{M1}(0 \le d_i \le 250,d_i &lt; d_{i+1} ) d1,d2,,dM1(0di250,di<di+1) ,即各列车的出发时间。第6、7行描述从第 n n n 站出发向左开的列车,格式同第4、5行。输出仅包含1行,即最少等待时间。无解输出 impossible.

解题思路:用 d p [ i ] [ j ] dp[i][j] dp[i][j] 来代表第 i i i 时刻在 j j j 车站的等待时间。在每一个车站,Mario有三种方法:1、等待1分钟
2、搭乘向左开的列车
3、搭乘向右开的列车
我们可以先假设终态为 d p [ T ] [ n ] = 0 dp[T][n]=0 dp[T][n]=0 ,然后再由终态往前推始态 d p [ 0 ] [ 1 ] dp[0][1] dp[0][1] ,如果 d p [ 0 ] [ 1 ] ≥ i n f dp[0][1] \ge inf dp[0][1]inf,则证明无法推到,输出impossible,否则输出 d p [ 0 ] [ 1 ] dp[0][1] dp[0][1] 的值即可。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int maxn = (int)1e5 + 5;
const ll mod = 1e9+7;
int dp[1200][120];
int d1[1200][120],d2[1200][120];
int t[120];
int sum1[120],sum2[120];
int main() 
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    #endif
    //freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(0),cin.tie(0);
    int n,T,c=0;
    while(scanf("%d",&n)!=EOF) {
    	if(n==0) break;
    	c++;
    	ms(sum1);ms(sum2);
    	ms(d1);ms(d2);
    	ms(t);
	    scanf("%d",&T);
	    rep(i,1,n-1) {
	    	scanf("%d",&t[i]);
	    	sum1[i]=sum1[i-1]+t[i];
	    }
	    lep(i,n-1,1) sum2[i]=sum2[i+1]+t[i];
	    int m1,m2;
	    scanf("%d",&m1);
	    int nape;
	    rep(i,1,m1) {
	    	scanf("%d",&nape);
	    	d1[nape][1]=1;
	    	rep(j,1,n-1) {
	    		d1[nape+sum1[j]][j+1]=1;
	    	}
	    }
	    scanf("%d",&m2);
	    rep(i,1,m2) {
	    	scanf("%d",&nape);
	    	d2[nape][n]=1;
	    	lep(j,n-1,1) {
	    		d2[nape+sum2[j]][j]=1;
	    	}
	    }
    	rep(i,1,n-1) 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&&d1[i][j]==1&&i+t[j]<=T)
	    			dp[i][j]=min(dp[i][j],dp[i+t[j]][j+1]);
	    		if(j>1&&d2[i][j]==1&&i+t[j-1]<=T)
	    			dp[i][j]=min(dp[i][j],dp[i+t[j-1]][j-1]);
	    	}
	    }
	    printf("Case Number %d: ",c);
	    if(dp[0][1]>=inf) printf("impossible\n");
	    else printf("%d\n",dp[0][1]);
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值