A Spy in the Metro(DAG上的动态规划)UVA - 1025

26 篇文章 13 订阅

原题链接: https://vjudge.net/problem/UVA-1025
在这里插入图片描述

测试样例

Sample Input
4
55
5 10 15
4
0 5 10 20
4
0 5 10 15
4
18
1 2 3
5
0 3 6 10 12
6
0 3 5 7 12 15
2
30
20
1
20
7
1 3 5 7 11 13 17
0
Sample Output
Case Number 1: 5
Case Number 2: 0
Case Number 3: impossible

题意: m 1 m1 m1个向右开的列车, m 2 m2 m2个向左开的列, n n n个车站。现在你从车站 1 1 1开始,进行某一操作:

  • 等车
  • 乘向右的列车(需要刚好有向右开的列车)
  • 乘向左的列车(需要刚好有向左开的列车)
    判断刚好在T时刻时到达车站 n n n,且需使得等待时间最少。

解题思路: 此道题我们很容易想到我们的策略就是少等车多乘车且最后一定要到达车站 n n n。而时间是单向流逝的,是一个天然的“序”。影响我们决策的只有当时所处的时间和所处的车站。 故我们状态可以用 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示,即在时间 i i i时所处车站 j j j所等待的最少时间。由于我们的最终状态 d p [ T ] [ n ] dp[T][n] dp[T][n]已经知道,我们需要逆向推导我们的初始状态 d p [ 0 ] [ 1 ] dp[0][1] dp[0][1],状态转移方程我们即可根据我们所选的操作取最优值即可。具体看AC代码,贴了详细注释。

AC代码

/*
*blog:https://blog.csdn.net/hzf0701
*邮箱:unique_powerhouse@qq.com
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)

using namespace std;

typedef long long ll;
const int maxn=1000;//数组所开最大值
const int mod=1e9+7;//模
const int inf=0x3f3f3f3f;//无穷大

int t[maxn];//其中t[i]代表第i个车站到第i+1个车站的时间。
bool has_train[maxn][maxn][2];//其中has_train[i][j][0]表示在i时刻j车站时有没有向右的车,has_train[i][j][1]则表示在i时刻j车站时有没有向左的车。
int dr[maxn],dl[maxn];//dr[i]表示向右开的第i个列车的起始出发时间,dl[i]表示向左开的第i个列车的起始出发时间。
int n,T,m1,m2;
int dp[maxn][maxn];//其中dp[i][j]表示时刻i,在车站j时还需要等待的时间。
int kase;
void init(){
    //初始化操作
    memset(has_train,false,sizeof(has_train));
    memset(dp,inf,sizeof(dp));
    //其中在时刻T,车站n时不需要等待了。
    dp[T][n]=0;
    rep(i,1,m1){
        int temp=dr[i];
        has_train[temp][1][0]=true;
        rep(j,1,n-1){
            temp+=t[j];
            has_train[temp][j+1][0]=true;
        }
    }
    rep(i,1,m2){
        int temp=dl[i];
        has_train[temp][n][1]=true;
        per(j,n-1,1){
            temp+=t[j];
            has_train[temp][j][1]=true;
        }
    }
}
void solve(){
    per(i,T-1,0){
        //代表时间的流逝。
        rep(j,1,n){
            //遍历车站替换最少等待时间。
            dp[i][j]=dp[i+1][j]+1;//等待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;
    }
}
int main(){
    kase=1;
    while(cin>>n){
        if(n==0)break;
        cin>>T;
        rep(i,1,n-1){
            cin>>t[i];
        }
        cin>>m1;
        rep(i,1,m1){
            cin>>dr[i];
        }
        cin>>m2;
        rep(i,1,m2){
            cin>>dl[i];
        }
        init();
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HeZephyr

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值