飞扬的小鸟(NOIP2014)(丧病DP题)

原题传送门

刚开始我还以为这道题目非常的简单。。

然后随便打了一个DP,直接WA,被zxyer狠狠地D了一顿。

然后发现有好多细节。。

首先假如某横坐标没有管子,那么l[x]=0;h[x]=m+1;

然后DP的时候往上是完全背包,往下是01背包。

由于不能接触到管子,所以0~l[x]和h[x]~m要设值inf方便下面判断。

m-max(q)*x[i]~m也要特判,因为有限高。。

最后统计答案也是很醉、。、

下面贴代码。。

#include<iostream> 
#include<cstdio> 
#include<cstdlib> 
#include<cstring> 
#include<algorithm> 
#define inf ((1<<31)-2) 
using namespace std; 
int f[10001][1001]; 
int n,m,k,ans; 
int x[10001],y[10001]; 
int l[10001],h[10001]; 
int main(){ 
    scanf("%d%d%d",&n,&m,&k); 
    for(int i=0;i<n;i++) 
    scanf("%d%d",&x[i],&y[i]); 
    for(int i=1;i<=n;i++) 
    l[i]=0,h[i]=m+1; 
    for(int i=1;i<=k;i++) 
    { 
    int p1,l1,h1; 
    scanf("%d%d%d",&p1,&l1,&h1); 
    l[p1]=l1;h[p1]=h1;   
    } 
    for(int i=1;i<=n;i++) 
    for(int j=0;j<=m;j++)f[i][j]=inf; 
    f[0][0]=inf; 
    for(int i=1;i<=n;i++) 
    { 
        for(int j=1;j<=m;j++) 
        { 
            if(j>=x[i-1]) 
            { 
                f[i][j]=min(f[i][j],f[i-1][j-x[i-1]]+1); 
                f[i][j]=min(f[i][j],f[i][j-x[i-1]]+1); 
            } 
            if(j==m) 
            { 
                for(int k=j-x[i-1];k<=m;k++) 
                { 
                    f[i][j]=min(f[i][j],f[i-1][k]+1); 
                    f[i][j]=min(f[i][j],f[i][k]+1); 
                } 
            } 
        } 
        for(int j=l[i]+1;j<h[i];j++) 
        if(j+y[i-1]<=m) 
        f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);   
        for(int j=1;j<=l[i];j++) 
        f[i][j]=inf; 
        for(int j=h[i];j<=m;j++) 
        f[i][j]=inf; 
    } 
    int cnt=k,ans=inf; 
    for(int i=n;i>=1;i--) 
    { 
        for(int j=l[i]+1;j<h[i];j++) 
        if(f[i][j]<inf) ans=min(ans,f[i][j]); 
        if(ans!=inf)break; 
        if(h[i]<=m)cnt--; 
    } 
    if(cnt==k) 
        printf("1
%d
",ans); 
    else 
        printf("0
%d
",cnt); 
    return 0; 
} 
原文地址:https://www.cnblogs.com/ghostfly233/p/6861597.html