zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    进程池线程池
    线程与其操作方法
    生产者消费者模型
    Java反射机制详解
    ajax跨域原理以及解决方案
    数据库连接池的选择 Druid
    新目标
    让webstorm支持avalon语法自动补全
    使用IDEA和gradle搭建Spring MVC和MyBatis开发环境
    使用IDEA自带的rest client参数传递乱码问题
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9822556.html
Copyright © 2011-2022 走看看