NOIP2014飞扬的小鸟

来源:互联网 发布:网络监控设计说明 编辑:程序博客网 时间:2024/05/01 05:37

http://www.luogu.org/problem/show?pid=1941#

我有话说:
这道题类似于完全背包问题。要注意细节问题。设dp(i,j)表示在坐标(i,j)时的最小点击屏幕次数。
状态转移方程:
dp(i,j)=min{dp(i-1,j-x[i-1])+1,dp(i,j-x[i-1])+1,dp(i-1,j+y[i-1])};

#include<iostream>#include<string>#include<cstring>#include<sstream>#include<vector>#include<algorithm>#include<queue>#include<cstdio>using namespace std;const int maxn=10000+10;const int maxm=1000+10;const int INF=100000000;const int mod=10007;int f[maxn][maxm];int x[maxn],y[maxn],down[maxn],up[maxn];int main(){    int n,m,a;    cin>>n>>m>>a;    for(int i=0;i<n;i++)scanf("%d%d",&x[i],&y[i]);    for(int i=1;i<=n;i++){down[i]=0;up[i]=m+1;}    int p,l,h;    for(int i=0;i<a;i++){        scanf("%d%d%d",&p,&l,&h);        down[p]=l;up[p]=h;    }    //for(int i=0;i<=n;i++)f[i][0]=INF;    //for(int j=1;j<=m;j++)f[n][j]=0;    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=down[i]+1;j<=up[i]-1;j++)if(j+y[i-1]<=m)            f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);//在dp(i-1,j+y[i-1])选择下落        for(int j=1;j<=down[i];j++)f[i][j]=INF;        for(int j=up[i];j<=m;j++)f[i][j]=INF;    }    /*for(int j=m;j>=0;j--){    for(int i=0;i<n;i++)        printf("%d ",f[i][j]==INF?9:f[i][j]);     printf("\n");    }*/    int ans=INF,cnt=a;    for(int i=n;i>=1;i--){//检验是否能到达        for(int j=down[i]+1;j<up[i];j++)            if(f[i][j]<INF)            ans=min(ans,f[i][j]);        if(ans!=INF)break;        if(up[i]<=m)cnt--;    }    if(cnt==a)printf("1\n%d\n",ans);    else printf("0\n%d\n",cnt);    return 0;}
0 0