算法竞赛入门经典--例题和课后训练(动态规划)

1.地铁间谍(逆序推导时间法)

特工玛利亚被送到S市执行一个特别危险的任务。她需要利用地铁完成他的任务,S市的地铁只有一条线路运行,所以并不复杂。

玛利亚有一个任务,现在的时间为0,她要从第一个站出发,并在最后一站的间谍碰头。玛利亚知道有一个强大的组织正在追踪她,她知道如果一直呆在一个车站,她会有很大的被抓的风险,躲在运行的列车中是比较安全的。所以,她决定尽可能地呆在运行的列车中,她只能往前或往后坐车。

玛利亚为了能准时且安全的到达最后一个车站与对方碰头,需要知道在在车站最小等待时间总和的计划。你必须写一个程序,得到玛丽亚最短的等待时间。当然,到了终点站之后如果时间还没有到规定的时刻,她可以在车站里等着对方,只不过这个等待的时刻也是要算进去的。

这个城市有n个车站,编号是1-n,火车是这么移动的:从第一个车站开到最后一个车站。或者从最后一站发车然后开会来。火车在每特定两站之间行驶的时间是固定的,我们也可以忽略停车的时间,玛利亚的速度极快,所以他可以迅速上下车即使两辆车同时到站。

输入输出格式

输入格式:

输入文件包含多组数据,每组数据都由7行组成

第1行:一个正整数N(2<=N<=50)表示站的数量

第2行:一个正整数T(0<=T<=200)表示需要的碰头时间

第3行:1-(n-1)个正整数(0<ti<70)表示两站之间列车的通过时间

第4行:一个整数M1(1<=M1<=50)表示离开第一个车站的火车的数量

第5行:M1个正整数:d1,d2……dn,(0<=d<=250且di<di+1)表示每一列火车离开第一站的时间

第6行:一个正整数M2(1<=M2<=50)表示离开第N站的火车的数量

第7行:M2个正整数:e1,e2……eM2,(0<=e<=250且ei<ei+1)表示每一列火车离开第N站的时间

最后一行有一个整数0。

输出格式:

对于每个测试案例,打印一行“Case Number N: ”(N从1开始)和一个整数表示总等待的最短时间或者一个单词“impossible”如果玛丽亚不可能做到。按照样例的输出格式。

输入输出样例

输入样例#1:

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

输出样例#1:

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

说明

第一组样例说明,她0分钟时上车,在3号站下车,立刻坐上(0分始发)15分开的车回去,到2号车站,立刻坐上(20分始发)25开的车到终点,50分到,还需要等待5分钟。

/*时间上的逆推法:由下一刻到t的最短时间来求当前时刻的最短时间,
注意这个题目中的预处理,解决了DP过程中需要判断能不能坐火车的问题(其他题目也要相互类比一下)
*/
#include<iostream>
using namespace std;
#include<cstdio>
#define N 501
#define T 2001
#define INF 1<<30
#include<cstring>
int n,t,tim[N],m1,trainm1[N],m2,trainm2[N];
int have_train[T][N][2];
int kase=0;
int f[T][N];
void input()
{
    memset(tim,0,sizeof(tim));
    memset(trainm1,0,sizeof(trainm1));
    memset(trainm2,0,sizeof(trainm2));
    memset(have_train,0,sizeof(have_train));
    memset(f,0,sizeof(f));
    scanf("%d",&t);
    for(int i=1;i<=n-1;++i)
    {
        scanf("%d",&tim[i]);
    }
    scanf("%d",&m1);
    for(int i=1;i<=m1;++i)
    {
        scanf("%d",&trainm1[i]);
        int k=1;

       for(int j=trainm1[i];k<=n;j+=tim[k-1])
        {
            have_train[j][k][0]=1;/*have_train[][][]记录第j时刻,第k个车站,0表示向右的地铁,1表示向左的地铁,这是预处理,DP的时候容易写出方程*/
            k++;
        }

    }
    scanf("%d",&m2);
    for(int i=1;i<=m2;++i)/*同样的预处理*/
    {
        scanf("%d",&trainm2[i]);
        int k=n;
        for(int j=trainm2[i];k>=1;j+=tim[k])
        {
            have_train[j][k][1]=1;
            k--;
        }

    }

}
void DP()
{
    for(int i=1;i<=n-1;++i)
    f[t][i]=INF;/*动规方程的边界条件,在第t时刻,到达了n车站的最小等待时间是0*/
    f[t][n]=0;
    for(int i=t-1;i>=0;--i)
      for(int j=1;j<=n;++j)
      {
          f[i][j]=f[i+1][j]+1;/*这表示玛利亚没有走,而是在原地等了一分钟,注意这个是用未来的时间推出现在的时间*/
          if(j<n&&have_train[i][j][0]&&i+tim[j]<=t)/*递推:在i时刻j车站有向右的地铁,那么乘车走向下一站,时间从下一站推导这一站*/
          f[i][j]=min(f[i][j],f[i+tim[j]][j+1]);
          if(j>1&&have_train[i][j][1]&&i+tim[j-1]<=t)
          f[i][j]=min(f[i][j],f[i+tim[j-1]][j-1]);
      }
}
int main()
{
    for(;;)
    {
        scanf("%d",&n);
        if(n==0)
        break;
        ++kase;
        printf("Case Number %d: ",kase);
        input();
        DP();
        if(f[0][1]>=INF)/*如果推出的在第0时刻,第一个点到终点的最短等待时间>INF,也就是无法到的,任何状态,任何乘车方法都到不了,那么就输出impossible,值得注意的是,这里的INF也相当于是一个标志*/
        printf("impossible");
        else printf("%d",f[0][1]);
        printf("\n");
    }
    return 0;
}

时间: 2024-08-14 20:34:22

算法竞赛入门经典--例题和课后训练(动态规划)的相关文章

算法竞赛入门经典 例题 3-4 回文串

输入一个字符串,求出其中最长的回文子串.子串的含义是:在原串中连续出现的字符串片段.回文的含义是:正着看和倒着看相同.如abba和yyxyy.在判断时,应该忽略所有标点符号和空格,且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符).输入字符串长度不超过5000,且占据单独的一行.应该输出最长的回文串,如果有多个,输出起始位置最靠左的. 样例输入:Confuciuss say:Madam,I'm Adam. 样例输出:Madam,I'm Adam #include <stdio

算法竞赛入门经典 例题 3-1 开灯问题

有n盏灯,编号为1-n,第1个人把所有灯打开,第2个人按下所有编号为2的倍数的开关(这些灯将被关掉),第3个人按下所有编号为3的倍数的开关(其中关掉的灯被打开,       开着灯将被关闭),依此类推.一共有k个人,问最后有哪些灯开着? 输入:n和k,输出开着的灯编号.k≤n≤1000. 样例输入:7  3 样例输出:1 5 6 7 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MA

算法竞赛入门经典 例题 3-2 蛇形填数

在n*n方阵里填入1,2,?,n*n,要求填成蛇形.例如n=4时方阵为 10    11   12   1 9    16   13   2 8    15   14   3 7     6     5    4 上面的方阵中,多余的空格只是为了便于观察规律,不必严格输出.n≤8. #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXN 10 int a[MAXN][MAXN]; i

《算法竞赛入门经典》动态规划复习

codevs 4979 数塔 1 #define N 100 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 int a[N][N],b[N][N],n; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;++i) 10 for(int j=1;j<=i;++j) 11 { 12 scanf("

算法竞赛入门经典训练指南

最近在看算法竞赛入门经典训练指南这本书,书中不错的算法我将在博客中发布,和大家共同学习. 题目: 在你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头).村里有m个骑士可以雇佣,一个能力值为m的骑士可以砍掉一个直径不超过x的头,且需要支付x个金币.如何雇佣骑士才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍一个头(且不能被雇佣两次). 输入格式: 输入包含多组数据.每组数据的第一行为正整数m和n(1<=m,n<=20 000):以下m行每行为一个整数,即恶龙每

算法竞赛入门经典-训练指南(10881-Piotr&#39;s Ants)

题目大意: 一根长度为L的木棍一堆蚂蚁爬,向左或向右,速度都为1,若两蚂蚁碰撞则同时转头(转身时间忽略不计),问T时间之后每只蚂蚁的位置: 输入:t,(t个样例),每个样例输入 L,T,n,接下来是n行每行两个数据,一个POS(位置),一个dir(方向): 输出:按输入顺序输出每只蚂蚁的最终位置,若处于碰撞状态则输出Turning,掉下去输出"Fell off": 解题思路: 本题类似于<挑战程序设计>的一道水题(POJ -1852  Ants),思路题:不过本题输入并不一

【算法竞赛入门经典】【第三章】课后习题(第二部分)

自从蓝桥杯之后,都没写博客了.今天将之前第三章还差的一部分习题答案补上. 3-4整数相加 这一题题目有提示,说选择合适的输入方式,即可简化问题.刚开始没想到cin,结果还用字符串来做,多亏别人提醒我一下,我才想起cin.惭愧啊.. #include <iostream> using namespace std; int main() { int a,b; char op; while(cin>>a>>op>>b){ switch(op){ case '+':

《算法竞赛入门经典(第二版)》pdf

下载地址:网盘下载 内容简介  · · · · · · <算法竞赛入门经典(第2版)>是一本算法竞赛的入门与提高教材,把C/C++语言.算法和解题有机地结合在一起,淡化理论,注重学习方法和实践技巧.全书内容分为12 章,包括程序设计入门.循环结构程序设计.数组和字符串.函数和递归.C++与STL入门.数据结构基础.暴力求解法.高效算法设计.动态规划初步.数学概念与方法.图论模型与算法.高级专题等内容,覆盖了算法竞赛入门和提高所需的主要知识点,并含有大量例题和习题.书中的代码规范.简洁.易懂,不

算法竞赛入门经典+挑战编程+USACO

下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发.   一.UVaOJ http://uva.onlinejudge.org  西班牙Valladolid大学的程序在线评测系统,是历史最悠久.最著名的OJ.   二.<算法竞赛入门经典> 刘汝佳  (UVaOJ  351道题)  以下部分内容摘自:http://sdkdacm.5d6d.com/thread-6-1-1.html   "AO