【NOIP2014】飞扬的小鸟

题解:首先设置一个状态dp[i][j]表示到达位置i高度为j的最小点击次数。

我们讨论一下:

在i-1为位置跳的情况----

(1)

cap[i][j]=min(cap[i][j],cap[i-1][j-up[i-1]]+1);//由i-1位置跳一次而来
cap[i][j]=min(cap[i][j],cap[i][j-up[i-1]]+1);//可以解决多次点击的叠加效果(自己理解一下)

(2)

for(int p=j-up[i-1];p<=m;p++)//当当前的高度为m时,显然可以由i-1位置的高度从j-up[i-1]到m到的状态转移过来
{
  cap[i][j]=min(cap[i][j],cap[i-1][p]+1);
  cap[i][j]=min(cap[i][j],cap[i][p]+1);
}

下落的情况------

for(int j=L[i]+1;j<=H[i]-1;j++)
{
  if(j+down[i-1]<=m)
    cap[i][j]=min(cap[i][j],cap[i-1][j+down[i-1]]);
}

以下是代码。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
#include<cstring>
#include<queue>
#include<stack>
#define MAXN 10010
#define LL long long int
using namespace std;
const int INF=1e9;
const int EPS=1e-8;
struct node{
    int l;
    int h;
    int w;
}t[MAXN];
int cap[10001][1001];//到达横坐标为i高度为j的地方的最小步数
int n,m,k;
int w[MAXN];
int L[MAXN],H[MAXN];
int up[MAXN],down[MAXN];
int main()
{
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    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=0;i<=n;i++)
        L[i]=0,H[i]=m+1;
    int p,l,h;
    for(int i=1;i<=k;i++)
        {
            scanf("%d%d%d",&p,&l,&h);
            t[i].w=p;t[i].l=l;t[i].h=h;
            w[p]=1;
            L[p]=l;
            H[p]=h;
        }
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            cap[i][j]=INF;
    cap[0][0]=INF;
    for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                {
                    if(j>=up[i-1])
                        {
                            cap[i][j]=min(cap[i][j],cap[i-1][j-up[i-1]]+1);
                            cap[i][j]=min(cap[i][j],cap[i][j-up[i-1]]+1);
                        }
                    if(j==m)
                        {
                            for(int p=j-up[i-1];p<=m;p++)
                                {
                                    cap[i][j]=min(cap[i][j],cap[i-1][p]+1);
                                    cap[i][j]=min(cap[i][j],cap[i][p]+1);
                                }
                        }
                }
            for(int j=L[i]+1;j<=H[i]-1;j++)
                {
                    if(j+down[i-1]<=m)
                        cap[i][j]=min(cap[i][j],cap[i-1][j+down[i-1]]);
                }
            for(int j=1;j<=L[i];j++) cap[i][j]=INF;
            for(int j=H[i];j<=m;j++) cap[i][j]=INF;
        }
    int ans=INF,tot=k;
    for(int i=n;i>=1;i--)
        {
            for(int j=L[i]+1;j<=H[i]-1;j++)
                if(cap[i][j]<INF)
                    ans=min(ans,cap[i][j]);
            if(ans!=INF) break;
            if(w[i]==1) tot--;
        }
    if(tot==k)
        {
            cout<<1<<endl;
            cout<<ans<<endl;
        }
    else
        {
            cout<<0<<endl;
            cout<<tot<<endl;
        }
    return 0;
}

 

posted @ 2017-08-01 14:21  楼主大大  阅读(409)  评论(3编辑  收藏  举报