zoukankan      html  css  js  c++  java
  • 九度oj 题目1086:最小花费

    题目描述:
    在某条线路上有N个火车站,有三种距离的路程,L1,L2,L3,对应的价格为C1,C2,C3.其对应关系如下:
    距离s           票价
    0<S<=L1         C1
    L1<S<=L2        C2
    L2<S<=L3        C3
    输入保证0<L1<L2<L3<10^9,0<C1<C2<C3<10^9。
    每两个站之间的距离不超过L3。
    当乘客要移动的两个站的距离大于L3的时候,可以选择从中间一个站下车,然后买票再上车,所以乘客整个过程中至少会买两张票。
    现在给你一个 L1,L2,L3,C1,C2,C3。然后是A B的值,其分别为乘客旅程的起始站和终点站。
    然后输入N,N为该线路上的总的火车站数目,然后输入N-1个整数,分别代表从该线路上的第一个站,到第2个站,第3个站,……,第N个站的距离。
    根据输入,输出乘客从A到B站的最小花费。
    输入:
    以如下格式输入数据:
    L1  L2  L3  C1  C2  C3
    A  B
    N
    a[2]
    a[3]
    ……
    a[N]
    输出:
    可能有多组测试数据,对于每一组数据,
    根据输入,输出乘客从A到B站的最小花费。
    样例输入:
    1 2 3 1 2 3
    1 2
    2
    2
    样例输出:
    2

    这道题真是一个惨痛的回忆。
    开始的思路是普通的动态规划思路,即经典的分割问题,最后通过的代码如下
     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <string>
     5 #define MAX 300
     6 #define inf 10000000009
     7 
     8 long long minCost[MAX][MAX];
     9 long long dis[MAX][MAX];
    10 long long dis0[MAX];
    11 
    12 int main(int argc, char const *argv[])
    13 {
    14     long long L1, L2, L3, C1, C2, C3;
    15     //freopen("input.txt","r",stdin);
    16     while(scanf("%lld %lld %lld %lld %lld %lld",&L1, &L2, &L3, &C1, &C2, &C3) != EOF)
    17     {
    18         int A, B;
    19         int N;
    20         scanf("%d %d",&A,&B);
    21         scanf("%d",&N);
    22         dis0[1] = 0;
    23         for(int i = 2; i <= N; i++) {
    24             scanf("%lld",&dis0[i]);
    25         }
    26         for(int l = 1; l <= N - 1; l++) {
    27             //length from 1 to N - 1
    28             for(int i = 1; i <= N - l; i++) {
    29                 //start from i to N - l
    30                 int j = i + l;
    31                 //end is i + l
    32                 dis[i][j] = dis0[j] - dis0[i];
    33                 if(dis[i][j] <= L1) {
    34                     minCost[i][j] = C1;
    35                 }
    36                 else if(dis[i][j] <= L2) {
    37                     minCost[i][j] = C2;
    38                 }
    39                 else if(dis[i][j] <= L3) {
    40                     minCost[i][j] = C3;
    41                 }
    42                 else {
    43                     minCost[i][j] = inf;
    44                 }
    45                 
    46                 for(int k = i + 1; k <= j-1; k++) {
    47                     long long int q = minCost[i][k] + minCost[k][j];
    48                     if(q < minCost[i][j]) {
    49                         minCost[i][j] = q;
    50                     }
    51                 }
    52             }
    53         }
    54         if(A < B) {
    55             printf("%lld
    ",minCost[A][B]);
    56         }
    57         else if(A > B){
    58             printf("%lld
    ",minCost[B][A]);
    59         }
    60         else {
    61             printf("%d
    ",0);
    62         }
    63 
    64     }
    65     return 0;
    66 }

    但代码一开始提交了n次都没有通过,经过很长时间的排查,终于发现了原因。一开始我设的inf是

    1000000009,WA改成了

    10000000009后就AC了。

    之后我发现没必要去算出每两个点之间的最小花费,只需要计算出从A到B之间的最小花费即可,dis数组也不需要

    代码如下:

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <string>
     5 #define MAX 300
     6 #define inf 10000000009
     7 
     8 long long minCost[MAX][MAX];
     9 long long dis0[MAX];
    10 
    11 int main(int argc, char const *argv[])
    12 {
    13     long long L1, L2, L3, C1, C2, C3;
    14     //freopen("input.txt","r",stdin);
    15     while(scanf("%lld %lld %lld %lld %lld %lld",&L1, &L2, &L3, &C1, &C2, &C3) != EOF)
    16     {
    17         int A, B;
    18         int N;
    19         scanf("%d %d",&A,&B);
    20         scanf("%d",&N);
    21         
    22         for(int i = 2; i <= N; i++) {
    23             scanf("%lld",&dis0[i]);
    24         }
    25         if(A > B) {
    26             int temp = A;
    27             A = B;
    28             B = temp;
    29         }
    30         long long n = B - A;
    31         dis0[1] = 0;
    32         minCost[A][A] = 0;
    33         for(int l = 1; l <= n; l++) {
    34             //length from 1 to N - 1
    35             for(int i = A; i <= A + n - l; i++) {
    36                 //start from i to N - l
    37                 int j = i + l;
    38                 //end is i + l
    39                 long long temp = dis0[j] - dis0[i];
    40                 if(temp <= L1) {
    41                     minCost[i][j] = C1;
    42                 }
    43                 else if(temp <= L2) {
    44                     minCost[i][j] = C2;
    45                 }
    46                 else if(temp <= L3) {
    47                     minCost[i][j] = C3;
    48                 }
    49                 else {
    50                     minCost[i][j] = inf;
    51                 }
    52                 
    53                 for(int k = i + 1; k <= j-1; k++) {
    54                     long long int q = minCost[i][k] + minCost[k][j];
    55                     if(q < minCost[i][j]) {
    56                         minCost[i][j] = q;
    57                     }
    58                 }
    59             }
    60         }
    61         printf("%lld
    ",minCost[A][B]);
    62 
    63     }
    64     return 0;
    65 }

     但是我们研究一下会发现,如果两地的距离小于L3,则它们之间的最小花费必然在C1,C2,C3之间,所以若将minCost改为一维数组,将i作为中间点,j作为终点,当i到j的距离小于L3时,minCost[j] = min (minCost[j], minCost[i] + Ci); 所以遍历i时,选取与其距离小于L3的j,即可。代码如下:

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <string>
     5 #define MAX 150
     6 #define inf 10000000009
     7 
     8 long long minCost[MAX];
     9 long long dis0[MAX];
    10 
    11 int main(int argc, char const *argv[])
    12 {
    13     long long L1, L2, L3, C1, C2, C3;
    14     //freopen("input.txt","r",stdin);
    15     while(scanf("%lld %lld %lld %lld %lld %lld",&L1, &L2, &L3, &C1, &C2, &C3) != EOF)
    16     {
    17         int A, B;
    18         int N;
    19         
    20         scanf("%d %d",&A,&B);
    21         scanf("%d",&N);
    22         dis0[1] = 0;
    23         for(int i = 2; i <= N; i++) {
    24             scanf("%lld",&dis0[i]);
    25             minCost[i] = inf;
    26         }
    27         if(A > B) {
    28             int temp = A;
    29             A = B;
    30             B = temp;
    31         }
    32         minCost[A] = 0;
    33         for(int i = A; i < B; i++) {
    34             for(int j = i + 1; j <= B; j++) {
    35                 long long int temp;
    36                 if(dis0[j] - dis0[i] <= L1) {
    37                     temp = C1;
    38                 }
    39                 else if(dis0[j] - dis0[i] <= L2) {
    40                     temp = C2;
    41                 }
    42                 else if(dis0[j] - dis0[i] <= L3) {
    43                     temp = C3;
    44                 }
    45                 else {
    46                     break;
    47                 }
    48                 long long q = minCost[i] + temp;
    49                 if(minCost[j] > q) {
    50                     minCost[j] = q;
    51                 }
    52             }
    53         }
    54         printf("%lld
    ",minCost[B]);
    55     }
    56     return 0;
    57 }

     因为两个站的最大距离不超过L3,所以从A站到j站,中间必然会经过距离j站距离小于L3的某站,故minCost[j]在遍历时中间的分割点必然在这些站之间,所以可以这样化简

  • 相关阅读:
    第五章 项目范围管理
    一位华为IT总监的12大职场经验谈
    接到面试通知后该做什么
    经验借鉴:外包失败三条血泪经验分享
    项目范围管理收集需求
    绝对不能对老板说的十句傻话
    项目整合实施整体变更控制
    项目整合结束项目或阶段
    9招助你夺取更高职位
    IT人写好简历的原则与方法
  • 原文地址:https://www.cnblogs.com/jasonJie/p/5682183.html
Copyright © 2011-2022 走看看