[NOIP2014] 飞扬的小鸟 【背包】

题目

很明显的背包问题,向上飞可以点无限次,所以是完全背包,向下掉只可能掉一次,所以是01背包。又因为不能在掉落之后再上升,所以要先算完全背包

我开始用的是递推,75分(TLE5个点…),对于每一列能够到达的点,推出下一行所能到达的点(所以就重复计算了很多次,完全没有用到背包的思想)

接着开始考虑背包,对于一列i的纵坐标j,f[i][j]表示到达这个点需要点击的最小次数,那么

f[i][j]=min{f[i-1][j-up]+1,f[i][j-up]+1,f[i-1][j+down]};

然后就是i,j到底应该在哪个范围内怎么取的问题了,特别傻逼的我认为j必须要大于这一列的下面那一根水管的高度,然后就开始了

for(int i=1; i <= n; i++)
    for(int j=max(bottom[i],up[i]); j <= top[i]; j++)

结果可想而知
因为有可能前面几次点击屏幕的时候鸟还低于下面的水管,而如果这么算的话前面几次点击屏幕的就无法被记录到了,就有可能会无法通过水管(我被这东西卡了好久,然后赌运气把第二个循环的范围换了,结束之后再把无法到达的点初始化就A了…)

还是有很多其他细节要处理的(感觉每次写NOIP的题都是跪在细节上)

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
const int N=10010, M=1010, inf=100000010;
int n, m, k, flag=1;
int f[N][M], pip[N], top[N], bot[N], up[N], down[N];

int solve()
{
    int flag1, ans1=0;
    for(int i=1; i <= n; i++)
    {
        flag1=0;
        for(int j=up[i]; j <= m; j++)
        {
            if(j == m)
                for(int u=m-up[i]; u <= m; u++)
                {
                    if(f[i][j] > f[i-1][u]+1) f[i][j]=f[i-1][u]+1;
                    if(f[i][j] > f[i][u]+1) f[i][j]=f[i][u]+1;
                }
            if(f[i][j] > f[i-1][j-up[i]]+1) f[i][j]=f[i-1][j-up[i]]+1;
            if(f[i][j] > f[i][j-up[i]]+1) f[i][j]=f[i][j-up[i]]+1;
            if(f[i][j] != inf && j < top[i] && j > bot[i]) flag1=1;
        }
        for(int j=1; j <= m; j++){
            if(j+down[i] < top[i-1] && j+down[i] > bot[i-1] && f[i][j] > f[i-1][j+down[i]]) f[i][j]=f[i-1][j+down[i]];
            if(f[i][j] != inf && j < top[i] && j > bot[i]) flag1=1;
            //printf("%d %d %d %d %d %d %d\n",i,j,bot[i],top[i],up[i],down[i],f[i][j]);
        }
        if(!flag1) {flag=0; return ans1;}
        for(int j=0; j <= bot[i]; j++) f[i][j]=inf;
        for(int j=top[i]; j <= m; j++) f[i][j]=inf;
        if(pip[i]) ans1++;
    }
    int ans=inf;
    for(int i=1; i <= m; i++) if(f[n][i] < ans) ans=f[n][i];
    return ans;
}

int read(){
    int out=0, f=1; char c=getchar(); while(c < '0' || c > '9') {if(c == '-') f=-1; c=getchar();}
    while(c >= '0' && c <= '9') {out=(out<<1)+(out<<3)+c-'0'; c=getchar();}
    return out*f;
}

void init()
{
    //freopen("testdata.in","r",stdin);
    n=read(), m=read(), k=read();int x;
    for(int i=1; i <= n; i++) up[i]=read(), down[i]=read();
    for(int i=1; i <= k; i++)  x=read(), pip[x]=1, bot[x]=read(), top[x]=read();
    for(int i=0; i <= n; i++) if(!pip[i]) top[i]=m+1;
    for(int i=1; i <= n; i++)
        for(int j=0; j <= m; j++)
            f[i][j]=inf;
}

int main()
{
    init();
    int ans=solve();
    printf("%d\n%d\n", flag, ans);
    return 0;
}
posted @ 2017-12-22 18:36  zerolt  阅读(94)  评论(0编辑  收藏  举报