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\n%d",minn);
    } else {
        int ans=0;
        for(int i=0; i<=maxn; i++)
            if(vis[i])ans++;
        printf("0\n%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\n%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\n%d",ans);
    }
    return 0;
}

posted @ 2018-09-19 17:07  _Lancy  阅读(166)  评论(0编辑  收藏  举报