1025 A Spy in the metro 【DP】

题目大意

传送门
输入数据:

int n;//车站数
int T;//到T时刻到车站n
int t[Train_Num];//车站i到i+1之间的行驶时间
int M1;//第一站向右开的列车的数目
int d1[Train_Num];//M1个列车开的时间
int M2;//第n站向左开的列车的数目
int d2[Train_Num];//M2个列车开的时间

间谍0时刻在站台1,要在T时刻到达站台n,间谍可以在车站内等车来,尽量让等的时间总和最少,求等的时间总和。

样例

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

output

Case Number 1: 5
Case Number 2: 0
Case Number 3: impossible

解释

用dp[i][j]表示i时刻在j站台要等的时间。
那么dp[55][4] = 0
dp[50][4] = 5
dp[35][3] = 5
dp[25][2] = 5
dp[15][3] = 5
dp[5][2] = 5
dp[0][1] = 5

思路

在一个站台一共有三种策略:

  • 等一个时刻
  • 如果有开往左边的车,坐上开往左边的车
  • 如果有开往右边的车,坐上开往右边的车

代码

/**
 *    > Author:   whpointz
 *    > Mail:     506273980@qq.com
 *    > Github:   https://www.github.com/whpointz
 *    > Description:
 *
 *    > Created Time: 2017/08/05 16:38:09
**/
#include <stdio.h>
#include <cstring>
#define Train_Num 55
#define Time_Num 205
#define INF 1000

#define max(a,b) (a>b)? a:b //注意括号
#define min(a,b) (a>b)? b:a
int n;//车站数
int T;//到T时刻到车站n
int t[Train_Num];//车站i到i+1的行驶时间
int M1;//第一站向右开的列车的数目
int d1[Train_Num];//M1个列车开的时间
int M2;//第n站向左看的列车的数目
int d2[Train_Num];//M2个列车开的时间

int dp[Time_Num][Train_Num];//i时刻在车站j 最少需要等待的时间

int has_train[Time_Num][Train_Num][2];//i时刻在车站T,向右是否有车,向左是否有车

int main(){
    int kase = 1;
    while (scanf("%d", &n) && n != 0){

        //input
        scanf("%d", &T);
        for (int i = 1; i < n; i++) scanf("%d", &t[i]);
        scanf("%d", &M1);
        for (int i = 1; i <= M1; i++) scanf("%d", &d1[i]);
        scanf("%d", &M2);
        for (int i = 1; i <= M2; i++) scanf("%d", &d2[i]);

        //init
        dp[T][n] = 0;//初始状态 T时刻在车站n 需要等待的时间为0

        memset(has_train, 0, sizeof(has_train));
        //right
        for (int i = 1; i <= M1; i++)
        {
            int T_sum = d1[i];
            for (int j = 1; j < n; j++){
                has_train[T_sum][j][0] = 1;
                T_sum += t[j];
            }
        }
        //left
        for (int i = 1; i <= M2; i++)
        {
            int T_sum = d2[i];
            for (int j = n; j > 1; j--){
                has_train[T_sum][j][1] = 1;
                T_sum += t[j-1];
            }
        }

        for (int i = 1; i < n; i++) dp[T][i] = INF;
        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)//向右 i时刻j车站有车,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)//向左 i时刻j车站有车,i+t[j-1]<T 剪枝
                    dp[i][j] = min(dp[i][j], dp[i + t[j-1]][j - 1]);

                //printf("%d %d %d\n", i, j, dp[i][j]);
            }
        }
        printf("Case Number %d: ", kase++);
        if (dp[0][1] >= INF) 
            printf("impossible\n");
        else 
            printf("%d\n",dp[0][1]);
    }
}

Hit

has_train数组记录的时候,计算向左和向右是不一样的,我的方法中向左的车,j要减一。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值