• [noip 2014]飞扬的小鸟


    飞扬的小鸟

    题意:小鸟游戏,从最左边出发,到达最右边,假设,小鸟在(x,y),现在有两种走法,一种是点击K4,还有一种是保持不动,这两种情况分别可以让小鸟到(x+1,y+kX)。第二种情况是(x+1,y-Y)。地图中你有不可以到的地方,不能碰到水管和地面。现在求最小的点击次数,使得小鸟可以到达右边。(注意:不能超过最上面一行,点击以后,不会超过最上面一行)

    题解:这道题刚开始看是最短路,可以用djstela去做,但是会超时。每个起点开始,发现会超时。仔细一看,发现可以用背包做。就是一个01背包套一个完全背包的问题。01背包就是往下掉,完全背包是可以往上点,两种背包套在一起。子状态dp(i,j)代表最少需要点击几次到达(i,j)这个位置,不能到达就设成正无穷大。转移方程dp(i,j)=min(dp(i-1,j+Y),dp(i,j-X)),把不能到的地方在设成正无穷。如果不能到达,就从后往前找,找到第一个可以到的列,就是最远的列far,然后记录一下哪些列有水管,输出[1, far]里的水管即可。

    #include <iostream>
    #include <cstring>
    using namespace std;
    int n, m, k;
    int x[10010], y[10010];
    int dp[10010][2010];
    int low[10010], high[10010];
    bool flag[10010];
    int ans = 0x7f7f7f7f;
    int read() {
        int ret = 0, f = 1;
        char ch = getchar();
        while (!isdigit(ch)) {
            if (ch == '-') {
                f = -1;
            }
            ch = getchar();
        }
        while (isdigit(ch)) {
            ret = ret * 10 + ch - '0';
            ch = getchar();
        }
        return ret * f;
    }
    int main() {
        n = read(), m = read(), k = read();
        for (int i = 1; i <= n; i++) {
            x[i] = read();
            y[i] = read();
        }
        for (int i = 1; i <= n; i++) {
            high[i] = m + 1;
            low[i] = 0;
        }
        for (int i = 1, p; i <= k; i++) {
            p = read(), low[p] = read(), high[p] = read();
            flag[p] = 1;
        }
        memset(dp, 0x3f, sizeof(dp));
        for (int i = 1; i <= m; i++) {
            dp[0][i] = 0;
        }
        for (int i = 1; i <= n; i++) {
            for (int j = x[i] + 1; j <= m + x[i]; j++) {
                dp[i][j] = min(dp[i][j - x[i]] + 1, dp[i - 1][j - x[i]] + 1);
            }
            for (int j = m + 1; j <= x[i] + m; j++) {
                dp[i][m] = min(dp[i][j], dp[i][m]);
            }
            for (int j = 1; j + y[i] <= m; j++) {
                dp[i][j] = min(dp[i][j], dp[i - 1][j + y[i]]);
            }
            for (int j = 1; j <= low[i]; j++) {
                dp[i][j] = 0x3f3f3f3f;
            }
            for (int j = high[i]; j <= m; j++) {
                dp[i][j] = 0x3f3f3f3f;
            }
        }
        for (int i = 1; i <= m; i++) {
            ans = min(ans, dp[n][i]);
        }
        if (ans < 0x3f3f3f3f) {
            cout << 1 << endl;
            cout << ans;
        } else {
            ans = 0;
            cout << 0 << endl;
            int far = 0;
            for (int i = n; i >= 0; i--) {
                for (int j = 1; j <= m; j++) {
                    if (dp[i][j] < 0x3f3f3f3f) {
                        far = i;
                        break;
                    }
                }
                if (far) break;
            }
            for (int i = far; i; i--) {
                if (flag[i]) {
                    ans++;
                }
            }
            cout << ans;
        }
        return 0;
    }
  • 相关阅读:
    Linux 文件特殊权限 SUID SGID SBIT
    Oracle Flashback 详解
    Oracle RMAN备份与还原注意事项
    Linux df 与du用法
    Oracle RMAN备份与还原
    Oracle 不小心删除undo数据文件以及磁盘空间不足导致不能登录的解决办法
    Oracle 内存参数调优设置
    Oracle Profile 配置文件
    关于php语言的使用!
    分享几个Javascript 封装方法
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/11826973.html
Copyright © 2020-2023  润新知