zoukankan      html  css  js  c++  java
  • luogu 1941 飞扬的小鸟

    这道题对于第13个数据点,不知为什么f数组第二位开到2000以下就不能过,求指教

    飞扬的小鸟

    传送门

    题目大意

    一个小鸟在(n*m)的方阵里,然后有许多管道你们玩过就不多介绍了,然后每一个位置,点击会上升,不点击可以下降,点击效果可以叠加。
    求如果通关的最小点击次数,否则会最多通过多少个管道。

    solution

    30pts

    就是搜索,本以为会拿50pts。

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <cstdio>
    using namespace std;
    int n,m,k,up[20000],down[20000],vis[20000],flag,maxn,minn=0x7fffffff;
    struct edge {
        int u,d;
    } e[20000];
    void dfs(int x,int h,int tot) {
        if(h<=0) return ;
        maxn=max(maxn,x);
        if(x==n+1 && h>0) {
            flag=true;
            minn=min(minn,tot);
            return;
        }
        if(vis[x+1]) {
            for(int i=1; i<=3; i++) {
                if(h+up[x]*i<e[x+1].u && h+up[x]*i>e[x+1].d )dfs(x+1,((h+up[x]*i<=m)?(h+up[x]*i):m),tot+i);
            }
            if(h-down[x]<e[x+1].u && h-down[x]>e[x+1].d ) dfs(x+1,h-down[x],tot);
        } 
        else {
            for(int i=1; i<=3; i++) {
                dfs(x+1,((h+up[x]*i)<=m?(h+up[x]*i):m),tot+i);
            }
            dfs(x+1,h-down[x],tot);
        }
    }
    int main() {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0; i<=n-1; i++)
            scanf("%d%d",&up[i],&down[i]);
        for(int i=1; i<=k; i++) {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            vis[a]=1;
            e[a].u=c;
            e[a].d=b;
        }
        for(int i=0; i<=m; i++)
            if(vis[i] && i>e[i].d && i<e[i].u)
                dfs(0,i,0);
            else dfs(0,i,0);
        if(flag==true) {
            printf("1
    %d",minn);
        } else {
            int ans=0;
            for(int i=0; i<=maxn; i++)
                if(vis[i])ans++;
            printf("0
    %d",ans);
        }
        return 0;
    }
    

    100pts

    动态规划

    这道题如果细想,还真是可以用背包做,虽然限制条件多了一点。

    如果小鸟向上飞,则是完全背包。
    如果小鸟向下飞,则是01背包。
    如果小鸟遇到柱子,那么将此状态取消
    如果小鸟飞到m以上,那么定为m。

    最后输出倒叙查询dp数组就可以了

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int f[10010][2010];
    int n,m,k;
    int x[10010],y[10010];
    int vis[10010];
    int low[10010],high[10010];
    int main() {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1; i<=n; ++i) scanf("%d%d",&x[i],&y[i]);
        for(int i=1; i<=n; ++i) low[i]=1,high[i]=m;
        for(int i=1; i<=k; ++i) {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            vis[a]=1;
            low[a]=b+1;
            high[a]=c-1;
        }
        memset(f,0x3f,sizeof(f));
        for(int i=1; i<=m; ++i) f[0][i]=0;
        for(int i=1; i<=n; ++i) {
            for(int j=x[i]+1; j<=m+x[i]; ++j)
                f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);//如果向上飞
            for(int j=m+1; j<=m+x[i]; ++j)//将超过m的更新到m
                f[i][m]=min(f[i][m],f[i][j]);
            for(int j=1; j<=m-y[i]; ++j)//如果向下飞
                f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
            for(int j=1; j<low[i]; ++j)//遇到柱子直接g
                f[i][j]=f[0][0];
            for(int j=high[i]+1; j<=m; ++j)
                f[i][j]=f[0][0];
        }
        int ans=f[0][0];
        for(int j=1; j<=m; ++j)
            ans=min(ans,f[n][j]);
        if(ans<f[0][0]) printf("1
    %d",ans);
        else {
            int i,j;
            for(i=n; i>=1; i--) {
                for(j=1; j<=m; ++j)
                    if(f[i][j]<f[0][0]) break;
                if(j<=m) break;
            }
            ans=0;
            for(int p=1; p<=i; ++p)
                if(vis[p])ans++;
            printf("0
    %d",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    linux系统——机制与策略(三)
    linux系统——机制与策略(二)
    Linux系统——机制策略(一)
    RTSP会话基本流程
    linux编程学习
    编码风格——linux内核开发的coding style
    编程风格——整洁代码的4个提示
    编程风格——五种应该避免的代码注释
    十条不错的编程观点
    代码优化概要
  • 原文地址:https://www.cnblogs.com/ifmyt/p/9675568.html
Copyright © 2011-2022 走看看