洛谷P1941飞扬的小鸟——细节DP

题目:https://www.luogu.org/problemnew/show/P1941

此题主要注意许多细节,详见代码。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k,up[10005],down[10005],p[10005],l[10005],h[10005],f[10005][1005],wall[10005];
int INF=1e7;
bool vis[10005];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<n;i++)
        scanf("%d%d",&up[i],&down[i]);
    for(int i=1;i<=k;i++)
        scanf("%d%d%d",&p[i],&l[i],&h[i]),wall[p[i]]=i;
    memset(f,11,sizeof f);
    for(int j=1;j<=m;j++)f[0][j]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
//          if(wall[i]&&(j<=l[wall[i]]||j>=h[wall[i]]))continue;//不可部分!
            if(j==m)
                for(int k=0;k<=up[i-1]&&j-k>0;k++)//k=0
                {
                    if(!wall[i-1]||(wall[i-1]&&j-k>l[wall[i-1]]&&j-k<h[wall[i-1]]))
                        f[i][j]=min(f[i][j],min(f[i-1][j-k]+1,f[i][j-k]+1));
                    else f[i][j]=min(f[i][j],f[i][j-k]+1);
                }
            else if(j-up[i-1]>0)
            {
                if(!wall[i-1]||(wall[i-1]&&j-up[i-1]>l[wall[i-1]]&&j-up[i-1]<h[wall[i-1]]))
                    f[i][j]=min(f[i][j],min(f[i-1][j-up[i-1]]+1,f[i][j-up[i-1]]+1));
                else f[i][j]=min(f[i][j],f[i][j-up[i-1]]+1);
            }
            //不可又降又升
            if(f[i][j]<INF&&(!wall[i]||(wall[i]&&j>l[wall[i]]&&j<h[wall[i]])))
                vis[i]=1;
        }
        for(int j=1;j<=m;j++)
            if(j+down[i-1]<=m&&
                (!wall[i-1]||(wall[i-1]&&j+down[i-1]>l[wall[i-1]]&&j+down[i-1]<h[wall[i-1]])))
                {
                    f[i][j]=min(f[i][j],f[i-1][j+down[i-1]]);
                    if(f[i][j]<INF&&(!wall[i]||(wall[i]&&j>l[wall[i]]&&j<h[wall[i]])))
                        vis[i]=1;
                }
    }
    if(vis[n])
    {
        int mn=INF;
        for(int j=1;j<=m;j++)
            if(f[n][j]<mn)mn=f[n][j];
        printf("1\n%d",mn);
    }
    else
    {
        int nw,ans=0;
        for(int i=n;i>=1;i--)
            if(vis[i])
            {
                nw=i;
                break;
            }
        for(int i=1;i<=nw;i++)
            if(wall[i])ans++;
        printf("0\n%d",ans);
    }
    return 0;
}

  

posted @   Zinn  阅读(139)  评论(0编辑  收藏  举报
编辑推荐:
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
· .NET Core GC计划阶段(plan_phase)底层原理浅谈
阅读排行:
· 盘点!HelloGitHub 年度热门开源项目
· DeepSeek V3 两周使用总结
· 02现代计算机视觉入门之:什么是视频
· C#使用yield关键字提升迭代性能与效率
· 2. 什么?你想跨数据库关联查询?
点击右上角即可分享
微信分享提示