• 【NOIP2014提高组】飞扬的小鸟


    https://www.luogu.org/problem/show?pid=1941

    从某一点开始飞直到飞出地图最少点击屏幕的次数,显然只和该点的坐标唯一相关,没有后效性,考虑用DP解。
    令f(i,j)为从点(i,j)飞出地图最少点击次数。得状态转移方程:f(i,j)=min{f(i-1,j-k*x[i-1]+k), f(i-1,j+y[i-1])}
    其实就是完全背包和01背包的结合。时间复杂度为O(nm2)。
    初始状态:f(0,i)=0 (1<=i<=m),其他的都是∞。还得注意∞不能太大。

    特别的,当位置i没有水管时。f(i,m)=min{…, f(i-1,k)+1, f(i,k)+1}  (m-x[i-1]+1<=k<=m)
    这是因为高度在[m-x[i-1]+1, m]的鸟再跳一下就登顶了。 

    求解的时候顺便记录ans[i]=min{f(i,j)},如果出现了ans[i]=∞,说明到这里鸟就飞不动了,输出结果后直接结束。如果整个求解的过程都没有出现这种情况,说明鸟可以飞出去,ans[n]就是最终解。


    可以把第一维滚成2,优化空间复杂度。求解时用dp[i%2][j]代替dp[i][j],dp[(i-1)%2][j]代替dp[i-1][j]。不滚好像会MLE。

    既然是01背包和完全背包的结合,可以考虑套上完全背包的优化算法:把k拆开,得f(i,j)=min{f(i-1,j-x[i-1])+1, f(i,j-x[i-1])+1, f(i-1,j+y[i-1])},时间复杂度降为O(nm)。这时需要注意第二维先计算所有往上飞的状态,再计算往下掉的状态。否则f(i,j-x[i-1])+1有可能会变成一个时间内既往下掉又往上飞这种神奇的解。

    这题细节超多,我WA了无数次才过。随便举个例子:开始的时候我只计算两根水管中间的高度的状态,75分。然后改成计算所有高度的状态,完了之后再把有水管的位置赋值∞,神奇的A了。为什么会这样呢?

    如图↓↓↓。如果鸟在这个位置跳一下会撞水管,但是跳两下不会,也需要计算好跳一下撞水管的解。因为计算跳两下的解时候,需要用到跳一下的解。

    #include <iostream>
    #include <algorithm>
    #define maxn 10005
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int n, m, k;
    int x[maxn], y[maxn], l[maxn], h[maxn];
    bool exist[maxn];
    int dp[2][maxn];
    int main()
    {
        ios::sync_with_stdio(false);
        cin >> n >> m >> k;
        for (int i = 0; i < n; i++)
            cin >> x[i] >> y[i];
        for (int i = 0; i <= n; i++)
            h[i] = m + 1;
        int a;
        for (int i = 0; i < k; i++)
        {
            cin >> a;
            exist[a] = true;
            cin >> l[a] >> h[a];
        }
    
        dp[0][0] = inf;
        int cnt = 0, ans;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j <= m; j++)
                dp[i & 1][j] = inf;
    
            for (int j = x[i - 1] + 1; j <= h[i] - 1; j++) // 往上飞,注意有水管的位置也要计算
            {
                dp[i & 1][j] = min(dp[i & 1][j], dp[(i - 1) & 1][j - x[i - 1]] + 1);
                dp[i & 1][j] = min(dp[i & 1][j], dp[i & 1][j - x[i - 1]] + 1);
            }
            for (int j = m - x[i - 1] + 1; j <= h[i] - 1; j++) // 特殊处理高度m
            {
                dp[i & 1][m] = min(dp[i & 1][m], dp[i & 1][j] + 1);
                dp[i & 1][m] = min(dp[i & 1][m], dp[(i - 1) & 1][j] + 1);
            }
            for (int j = l[i] + 1; j <= min(m - y[i - 1], h[i] - 1); j++) // 往下掉
            {
                dp[i & 1][j] = min(dp[i & 1][j], dp[(i - 1) & 1][j + y[i - 1]]);
            }
    
            if (exist[i]) // 去掉水管位置的不合法解
            {
                for (int j = 0; j <= l[i]; j++)
                    dp[i & 1][j] = inf;
                for (int j = h[i]; j <= m; j++)
                    dp[i & 1][j] = inf;
            }
    
            ans = inf;
            for (int j = 1; j <= m; j++)
                ans = min(ans, dp[i & 1][j]);
            if (ans == inf)
            {
                cout << 0 << endl
                     << cnt << endl;
                return 0;
            }
            else if (exist[i])
                cnt++;
        }
        cout << 1 << endl
             << ans << endl;
        return 0;
    }
  • 相关阅读:
    bzoj4554: [Tjoi2016&Heoi2016]游戏
    bzoj3166: [Heoi2013]Alo
    luogu3398 仓鼠找sugar
    bzoj3261: 最大异或和
    bzoj3446: [Usaco2014 Feb]Cow Decathlon
    BZOJ1742[Usaco2005 nov]Grazing on the Run 边跑边吃草
    bzoj2750: [HAOI2012]Road
    bzoj4448: [Scoi2015]情报传递
    bzoj2809: [Apio2012]dispatching
    bzoj 1452
  • 原文地址:https://www.cnblogs.com/ssttkkl/p/7528862.html
Copyright © 2020-2023  润新知