欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

动态规划—洛谷 P1941 飞扬的小鸟

程序员文章站 2022-06-30 23:51:11
...

洛谷 P1941 飞扬的小鸟

动态规划—洛谷 P1941 飞扬的小鸟
动态规划—洛谷 P1941 飞扬的小鸟
动态规划—洛谷 P1941 飞扬的小鸟

分析

这显然是个dp问题,在每一列中,我没有两种选择:上升或下降。
上升:在每一列中可以无限次选择上升,恰好符合完全背包问题;
下降:通过题目知道,每列只能下降一次,正是01背包问题;
顶点的特判;
动态规划—洛谷 P1941 飞扬的小鸟
状态dp[i][j]表示到达点(i,j)花费的最少时间。
当前状态(红点)可以是由其他三个状态(蓝点,粉点,绿点)转移的
∴ f[i][j]=min(f[i][j+down[i-1]],f[i-1][j-up[i-1]],f[i][j-up[i]])
其中up[i],down[i]分别表示小鸟在第i列每次上升,下降的高度。
以下是代码实现:

#include<iostream>
#include<cmath>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[10005][2004];
int up[10005], down[10005];	//在i列上升下降的距离
int x[10005], s[10005];	//管道的下边沿高度和上边沿高度
bool f[10005];	//记录第i列是否有管道
int main()
{
    memset(dp, 0x3f, sizeof dp);	//把dp置为正无穷
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1; i <= n;i++)
    {
        cin >> up[i] >> down[i];
    }
    for (int i = 1; i <= k;i++)
    {
        int h;
        cin >> h;
        cin >> x[h] >> s[h];
        f[h] = 1;
    }
    for (int i = 1; i <= m;i++)
        dp[0][i] = 0;
    for (int i = 1; i <= n;i++)
    {
        for (int j = up[i] + 1; j <= m + up[i];j++)		//上升过程,完全背包
        {
            dp[i][j] = min(dp[i - 1][j - up[i]], dp[i][j - up[i]]) + 1;
        }
        for (int j = m + 1; j <= m + up[i]; j++)	//特判顶部
        {
            dp[i][m] = min(dp[i][m], dp[i][j]);
        }
        for (int j = 1; j <= m - down[i];j++)	//下降过程,01背包
        {
            dp[i][j] = min(dp[i][j], dp[i - 1][j + down[i]]);
        }
        if (f[i])	//将不能通过的点重置
        {
            for (int j = 1; j <= x[i];j++)
                dp[i][j] = dp[0][0];
            for (int j = s[i]; j <= m;j++)
            {
                dp[i][j] = dp[0][0];
            }
        }
    }
    int min1 = dp[0][0];
    for (int i = 1; i <= m;i++)
    {
        min1 = min(min1, dp[n][i]);
    }
    if (min1<dp[0][0])
    {
        cout << 1 << endl;
        cout << min1 << endl;
    }
    else
    {
        int i,j;
        for (i = n; i >= 1;i--)			//从后往前遍历,找到最后一次通过的一列
        {
            for (j = 1; j <= m;j++)
            {
                if (dp[i][j]<dp[0][0])
                    break;
            }
            if (j <= m)
                break;
        }
        int num = 0;		//记录通过的管道数
        for (j = 1; j <= i;j++)
        {
            if (f[j])
                num++;
        }
        cout << 0 << endl;
        cout << num << endl;
    }
        return 0;
}
相关标签: 动态规划 算法