码迷,mamicode.com
首页 > 其他好文 > 详细

P1941 飞扬的小鸟

时间:2018-10-13 02:22:53      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:效率   pts   lag   inf   clu   起点   阶段   algo   pre   

Flappy Bird真好玩(逃

这道题我一看上去好像是搜索啊,但是发现起点和终点都有点多了吧。。。

然后我就懵圈了。

其实这道题是一个套着皮的背包dp。

其实用dp想,很多问题就简单了。比如多个起点,我初值都设为0就行了;多个终点,我都找一遍就行了。

我自己试着不看题解自己用传统dp的思路(不夹杂任何背包)来写,用暴力做的完全背包,也拿到了75pts。很感动。

我们设\(dp[i][j]\)为小鸟到达\(i\)行高度为\(j\)时的最少点击数。

小鸟一次可以点击多次,上升多次。也可以不点,下降一次。

可以抽象成向上的完全背包和向下的01背包。

所以如何优化其实都告诉你了:像优化背包问题那样去写这道题。

有几个细节要注意:

  • 小鸟在高度为0处会死的。

  • 小鸟在高度为\(m\)的时候再跳还是\(m\),在本来会跳出\(m\)的时候只会跳到\(m\)

主要效率问题出现在完全背包的写法。

完全背包运用了这么一个思想:当前阶段的东西,可以由上一阶段装过来,还可以由现在阶段装过来。

所以在完全背包的时候写两句,一句针对上一阶段,一句针对当前阶段。也就是在这一秒多点击一次。

总的来说还是收获很多的。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
const int maxn = 10002, maxm = 1002;
const int INF = 0x3f3f3f3f;
int up[maxn], down[maxn];
int upblock[maxn], downblock[maxn];
int dp[maxn][maxm];
bool have[maxn];
int n, m, t;
int main()
{
    scanf("%d%d%d", &n, &m, &t);
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d", &up[i], &down[i]);
    }
    for(int i = 1; i <= t; i++)
    {
        int p, l, h; scanf("%d%d%d", &p, &l, &h);
        upblock[p] = h; downblock[p] = l;
        have[p] = true;
    }
    for(int i = 0; i <= n; i++)
    {
        if(!have[i])
        {
            downblock[i] = 0; upblock[i] = m + 1;
        }
    }
    memset(dp, 0x3f, sizeof dp);
    for(int i = 1; i <= m; i++) dp[0][i] = 0;
    int cnt = 0; bool failed = false;
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = up[i - 1]; j <= m; j++)
        {
            if(j == m)
            {
                for(int k = m - up[i - 1]; k <= m; k++)
                {
                    dp[i][j] = std::min(dp[i][j], dp[i - 1][k] + 1);
                    dp[i][j] = std::min(dp[i][j], dp[i][k] + 1);
                }
            }
            dp[i][j] = std::min(dp[i][j], dp[i - 1][j - up[i - 1]] + 1);
            dp[i][j] = std::min(dp[i][j], dp[i][j - up[i - 1]] + 1);
        }
        for(int j = downblock[i] + 1; j < upblock[i]; j++)
        {
            if(j + down[i - 1] >= upblock[i - 1] || j + down[i - 1] <= downblock[i - 1]) continue;
            dp[i][j] = std::min(dp[i][j], dp[i - 1][j + down[i - 1]]);
        }
        for(int j = 1; j <= downblock[i]; j++) dp[i][j] = INF;
        for(int j = upblock[i]; j <= m; j++) dp[i][j] = INF;
    }
    /*
    int temp1, temp2;
    while(scanf("%d%d", &temp1, &temp2) == 2 && temp1 != -1 && temp2 != -1)
    {
        printf("%d\n", dp[temp1][temp2]);
    }
    return 0;
    */
    
    int ans = INF;
    for(int i = 1; i <= m; i++) ans = std::min(ans, dp[n][i]);
    if(ans != INF)
    {
        printf("1\n%d\n", ans);
    }
    else
    {
        int i, j;
        bool flag = false;
        for(i = n; i >= 1; i--)
        {
            for(j = 1; j <= m; j++)
            {
                if(dp[i][j] != INF)
                {
                    flag = true;
                    break;
                }
            }
            if(flag) break;
        }
        int cnt = 0;
        for(int j = 1; j <= i; j++) if(have[j]) cnt++;
        printf("0\n%d\n", cnt);
    }
    return 0;
}

P1941 飞扬的小鸟

标签:效率   pts   lag   inf   clu   起点   阶段   algo   pre   

原文地址:https://www.cnblogs.com/Garen-Wang/p/9780994.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!