UVA1025简单的DP问题

这个题目其实还是很简单的,属于入门级别的动态规划

这道题的特点有如下几点:

第一:起点固定,终点固定

第二:在理解题意的时候,应该要理解到,如果有解,那么在T时刻,这货一定是在第n个station的。如果没有解,那么一定是第一趟从起点出发的列车在T之前走不到终点。

第三:虽然在列车上时,这货所在的位置也是能够确定的,但是这样就会带来很多的麻烦,不如直接忽略掉这部分。

下面是我使用记忆化搜索来写的dp解答:汝佳使用递推写的。

//状态是某个时刻在某个位置
//d(i,j)表示还需要在这个状态等多久,
//转移方程是,
//如果选择等一分钟,那么d(i,j) = d(i + 1,j) + 1
//如果此时有向右的火车(而且坐上这趟火车直到它停车的时候,不会超过T),那么d(i,j) = d(i + x,j + 1) + x;
//如果此时有向左的火车,那么d(i,j) = d(i + y,j - 1) + y;
//取这三者的最小值
//当然一开始得先设置d(T,k) = MAX; d(T,n) = 0;
//最后的结果如果可以正好到达,那不错
//如果不可以
//我刚才卡在了把   没有准时到达N点误解为了无解
//总的来说就是,找到所有可能的状态点,和在每一个状态点可行的决策(转移)方式,以及找到终点状态
//不管要等多久,都需要在最后的时刻处于最后一个station
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAX = 10000;


const int maxt = 300;
const int maxn = 55;

int have_train_right[maxt][maxn];
int have_train_left[maxt][maxn];
int gap[maxn];

int d[maxt][maxn];

int num_station;
int time;

//如果无解,绝对是从起点出发的列车太迟了,导致人停在了某一个地方无法移动,由于是求t1 t2 t3的最小值,所以一定是MAX

int dp(int t,int n)//计算t时刻,第n个station的需要等待的时间
{
    if(d[t][n] != -1)
        return d[t][n];
    //三种决策,计算最小的值
    int t1 = MAX,t2 = MAX,t3 = MAX;
    if(have_train_right[t][n] && t + gap[n] <= time)
    {
        t1 = dp(t + gap[n],n + 1);
    }
    if(have_train_left[t][n] && t + gap[n - 1] <= time)
    {
        t2 = dp(t + gap[n - 1],n - 1);
    }
    t3 = dp(t + 1,n) + 1;
    if(min(t1,t2) < t3)
    {
        d[t][n] = min(t1,t2);
    }
    else
        d[t][n] = t3;
    return d[t][n];
}

bool read_input()
{
    memset(d,-1,sizeof(d));
    memset(have_train_right,0,sizeof(have_train_right));
    memset(have_train_left,0,sizeof(have_train_left));
    memset(gap,0,sizeof(gap));
    scanf("%d%d",&num_station,&time);
    if(!num_station)
        return false;
    for(int i = 0;i < num_station - 1;i++)
    {
        scanf("%d",&gap[i]);
    }
    int M;
    scanf("%d",&M);
    for(int i = 0;i < M;i++)
    {
        int t;
        scanf("%d",&t);
        for(int j = 0;j < num_station - 1;j++)
        {
            have_train_right[t][j] = 1;
            t = t + gap[j];
            if(t > time)
                break;
        }
    }
    scanf("%d",&M);
    for(int i = 0;i < M;i++)
    {
        int t;
        scanf("%d",&t);
        for(int j = num_station - 1;j > 0;j--)
        {
            have_train_left[t][j] = 1;
            t = t + gap[j - 1];
            if(t > time)
                break;
        }
    }
    for(int i = 0;i < num_station - 1;i++)
    {
        d[time][i] = MAX;
    }
    d[time][num_station - 1] = 0;
    return true;
}


int main()
{
#ifdef local
    freopen("input.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int kase = 0;
    while(read_input())
    {
        printf("Case Number %d: ",++kase);
        int x = dp(0,0);
        if(x >= MAX)
        {
            printf("impossible\n");
        }
        else
            printf("%d\n",x);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/TorettoRui/p/10478054.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值