【DP】UOJ#17 【NOIP2014】飞扬的小鸟

题面在这里

很显然是一个DP……

fi,j 表示到 (i,j) 这个位置的最小步数

fi,j=Min{fi1,jkxi1+1,fi1,j+yi1}

但是转移需要 O(m) ,显然不行

发现 fi,j 有很大一部分的状态都可以由 fi,jxi1 转移来,剩下只有1个状态

那么我们先不考虑下落,刷一遍,然后再更新下落的答案

注意:此题细节很多,小鸟的飞行收到诸多限制

我们可以采用逐一排除的方法:先不考虑下落及m高度,还有水管的障碍,然后刷出下落的答案,最后把水管所在位置全部赋为INF

这样就很清晰了

示例程序:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define cl(x,y) memset(x,y,sizeof(x))
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int red(){
    int res=0,f=1;char ch=nc();
    while (ch<'0'||'9'<ch) {if (ch=='-') f=-f;ch=nc();}
    while ('0'<=ch&&ch<='9') res=res*10+ch-48,ch=nc();
    return res*f;
}

const int maxn=10005,maxm=1005,INF=0x3f3f3f3f;
int n,m,q,up[maxn],down[maxn],f[maxn][maxm],pos[maxn];
bool vis[maxn][maxm];
int main(){
    n=red(),m=red(),q=red();
    for (int i=0;i<n;i++) up[i]=red(),down[i]=red();
    for (int i=1;i<=q;i++){
        int x=red(),l=red(),h=red();pos[i]=x;
        for (int j=1;j<=l;j++) vis[x][j]=1;
        for (int j=h;j<=m;j++) vis[x][j]=1;
    }
    cl(f,63);
    for (int i=1;i<=m;i++) f[0][i]=0;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            if (j>up[i-1]) f[i][j]=min(f[i-1][j-up[i-1]],f[i][j-up[i-1]])+1;
        }
        for (int j=m-up[i-1];j<=m;j++)
         f[i][m]=min(f[i][m],min(f[i-1][j],f[i][j])+1);
        for (int j=1;j<=m;j++){
            if (j+down[i-1]<=m) f[i][j]=min(f[i][j],f[i-1][j+down[i-1]]);
        }
        for (int j=1;j<=m;j++) if (vis[i][j]) f[i][j]=INF;
    }
    int ans=INF,cnt=q;
    for (int j=1;j<=m;j++) ans=min(ans,f[n][j]);
    if (ans<INF) return printf("1\n%d",ans),0;
    for (int i=n-1;i;i--){
        bool suc=0;
        for (int j=1;j<=m;j++)
         if (f[i][j]<INF) {suc=1;break;}
        if (suc) break;
        if (vis[i][m]) cnt--;
    }
    printf("0\n%d",cnt);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值