P1941 飞扬的小鸟

Posted lltyyc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1941 飞扬的小鸟相关的知识,希望对你有一定的参考价值。

传送门

很显然的DP

我们设 f [ i ] [ j ] 表示在位置 i , j 时需要的最少的点击次数

考虑不点击的影响 f [ i ] [ j ] = f [ i-1 ] [ j + y [ i ] ]

如果点击 f [ i ] [ j ] = f [ i-1 ] [ j - x [ i ] ] +1 ,但是由于同一时间内可以点击多次,所以 f [ i ] [ j ] 可以从同一横坐标的位置转移过来

即  f [ i ] [ j ] = min(f [ i-1 ] [ j - x [ i ] ],f [ i ] [ j - x [ i ] ])+1(for循环时 j 从小到大)

注意题目的一个小坑

到最上面不会死也不会再上升

所以要特殊考虑

一定要注意不能直接把管子的位置判死,因为这个一直WA

可能上一步点击一次下一步会到管道,但是再点一次就不会碰到管道

因为我们转移有从同一横坐标转移(表示点了多次),所以先全部转完了再把管道位置的值弄成INF

大概就这样,具体实现看代码..

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9) { if(ch==-) f=-1; ch=getchar(); }
    while(ch>=0&&ch<=9) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=10007,M=1007,INF=2e9+7;

int u[N],d[N],a[N],b[N],n,m,t;//u[i],d[i]分别表示横坐标i的管道的上下部分,a[i],b[i]表示横坐标i的上升下降距离
int f[N][M],ans;

int main()
{
    memset(f,0x7f,sizeof(f));
    int pos;
    n=read(); m=read(); t=read();
    for(int i=1;i<=n;i++) a[i]=read(),b[i]=read(),u[i]=m+1;
    for(int i=1;i<=t;i++) pos=read(),d[pos]=read(),u[pos]=read();
    
    pos=0; bool flag;
    for(int i=1;i<=m;i++) f[0][i]=0;//一开始可以在任何位置
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<u[i];j++) if(j-a[i]>0) f[i][j]=min(f[i][j] ,min(f[i-1][j-a[i]]+1,f[i][j-a[i]]+1) );//考虑上一位置多次点击的转移
        if(u[i]>m) for(int j=m-a[i]+1;j<=m;j++) f[i][m]=min(f[i][m], min(f[i-1][j]+1,f[i][j]+1) );//特殊考虑最高处的转移
        for(int j=d[i]+1;j<u[i];j++) if(j+b[i]<=m) f[i][j]=min(f[i][j],f[i-1][j+b[i]]);//考虑上一位置不点击的转移
        
        for(int j=1;j<=d[i];j++) f[i][j]=f[0][0];//先转完再把管道位置弄成INF
        flag=0;
        for(int j=1;j<=m;j++) if(f[i][j]<f[0][0]) flag=1;
        if(!flag) { pos=i; break; }//判断能否到达终点,如果当前横坐标任意位置都无法到达说明最多到此处
    }
    
    if(pos)//如果无法到达
    {
        ans=0;
        for(int i=1;i<pos;i++) if(d[i]||u[i]<=m) ans++;//计算经过多少管道
        printf("0
%d",ans);
        return 0;
    }
    //否则
    ans=INF;
    for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);//计算最少步数
    printf("1
%d",ans);
    return 0;
}

 

以上是关于P1941 飞扬的小鸟的主要内容,如果未能解决你的问题,请参考以下文章

luogu P1941 飞扬的小鸟

P1941 飞扬的小鸟(背包)

P1941 飞扬的小鸟

P1941 飞扬的小鸟

P1941 飞扬的小鸟

P1941 飞扬的小鸟