• [luoguP1941] 飞扬的小鸟(DP)


    传送门

    动归,用f[i][j]表示到达第I列高度为j时最少需要飞的次数,容易想到最裸的转移:

    f[i][j]=min(min(f[i-1][j-up[i-1]*k]+k),f[i-1][j+down[i-1]])

    但是会超时

    考虑怎么优化k的循环,发现k可以从k-1转移过来,从图上来理解就是比如k=2时,相当于可以先从i-1列飞一次飞到i列的j-up[i-1]位置,然后再往上跳一次跳到i的j位置,也就是f[i][j]可以从f[i]

    [j-up[i-1]]+1转移来,这里需要注意几个地方

    1.由于f[i][j-up[i-1]]相当于是中转的位置,所以无论那个位置是不是管道都要做

    2.要保证f[i][j-up[i-1]]可以充当中转,所以必须先做一次只飞不掉的,再做一次掉下来的,否则会出现f[i][j-up[i-1]]位置可能是从i-1列掉下来得到的,此时不能充当中转

    3.要特殊处理高度为m的情况(看题目)

    ——代码

     1 #include <cstdio>
     2 #include <iostream>
     3 
     4 const int INF = 19260817, N = 10001, M = 1001;
     5 int n, m, k, b, ans = INF, sum;
     6 int x[N], y[N], l[N], h[N], f[2][M];
     7 
     8 inline int read()
     9 {
    10     int x = 0, f = 1;
    11     char ch = getchar();
    12     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    13     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    14     return x * f;
    15 }
    16 
    17 inline int min(int x, int y)
    18 {
    19     return x < y ? x : y;
    20 }
    21 
    22 int main()
    23 {
    24     int i, j, p;
    25     n = read();
    26     m = read();
    27     k = read();
    28     for(i = 0; i < n; i++)
    29     {
    30         x[i] = read();
    31         y[i] = read();
    32     }
    33     for(i = 1; i <= k; i++)
    34     {
    35         p = read();
    36         l[p] = read();
    37         h[p] = read();
    38     }
    39     for(i = 1; i <= n; i++)
    40     {
    41         for(j = 1; j <= m; j++) f[i & 1][j] = INF;
    42         for(j = x[i - 1] + 1; j <= m; j++)
    43             f[i & 1][j] = min(f[i & 1][j], f[i & 1 ^ 1][j - x[i - 1]] + 1),
    44             f[i & 1][j] = min(f[i & 1][j], f[i & 1][j - x[i - 1]] + 1);
    45         for(j = m - x[i - 1]; j <= m; j++)
    46             f[i & 1][m] = min(f[i & 1][m], f[i & 1 ^ 1][j] + 1),
    47             f[i & 1][m] = min(f[i & 1][m], f[i & 1][j] + 1); 
    48         for(j = 1; j <= m - y[i - 1]; j++) f[i & 1][j] = min(f[i & 1][j], f[i & 1 ^ 1][j + y[i - 1]]);
    49         if(l[i]) for(j = 1; j <= l[i]; j++) f[i & 1][j] = INF;
    50         if(h[i]) for(j = h[i]; j <= m; j++) f[i & 1][j] = INF;
    51         if(l[i] || h[i])
    52         {
    53             b = 0;
    54             for(j = l[i] + 1; j < h[i]; j++)
    55                 if(f[i & 1][j] < INF)
    56                 {
    57                     b = 1;
    58                     break;
    59                 }
    60             if(b) sum++;
    61             else break;
    62         }
    63     }
    64     if(i == n + 1)
    65     {
    66         for(j = 1; j <= m; j++) ans = min(ans, f[n & 1][j]);
    67         printf("1
    %d
    ", ans);
    68     }
    69     else printf("0
    %d
    ", sum);
    70     return 0;
    71 }
    View Code
  • 相关阅读:
    Microsoft Web Camp
    [程序员学英语]26个英文字母
    原来接口是这样用的!一个例子搞定接口
    BizTalk Server 2010 培训
    [PM Tools]软件项目进度跟踪表v4.0
    BizTalk 开发系列(四十一) BizTalk 2010 BAM 安装手记
    WCF服务编程HelloWorld
    BizTalk 开发系列(三十九) BizTalk Server 2009技术概览
    WCF服务编程WCF应用程序的消息跟踪
    WCF服务编程基础
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6889462.html
Copyright © 2020-2023  润新知