P1941 飞扬的小鸟

传送门

思路:

  动态规划,设 f [ i ][ j ] 表示小鸟到达坐标( i , j ) 所要点击屏幕的最少次数,如果小鸟无法到达( i , j ),则 f [ i ][ j ] = INF。

  转移,考虑小鸟上升,和下降两种状态。

  因为,在一个点上升次数不限,下降只有一次。

  所以上升可以用 完全背包 的状态转移,下降用 01背包 转移。

  特判,当小鸟到达顶上 m 时,如果继续点击屏幕,小鸟不会上升、死亡,也不会掉下来,但是屏幕点击次数要 +1 。

Code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<stack>
#include<vector>
#include<queue>
#include<deque>
#include<map>
#include<set>
using namespace std;
#define lck_max(a,b) ((a)>(b)?(a):(b))
#define lck_min(a,b) ((a)<(b)?(a):(b))
typedef long long LL;
const int maxn=10005;
const int INF=1e9+7;
LL n,m,k,i,j,ans=INF;
LL f[maxn][4005];
struct hh
{
    LL x,y;
}t[maxn];
struct hhh
{
    LL low,high;bool p;
}g[maxn];
inline LL read()
{
    LL kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(!(ls^45))
            kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return xs*kr;
}
inline void out(LL xs)
{
    if(!xs) {putchar(48); return;}
    if(xs<0) putchar('-'),xs=-xs;
    int kr[57],ls=0;
    while(xs) kr[++ls]=xs%10,xs/=10;
    while(ls) putchar(kr[ls]+48),ls--;
}
int main()
{
    LL a,b,c;
    n=read();m=read();k=read();
    for(i=1;i<=n;i++)
        t[i].x=read(),t[i].y=read(),g[i].low=1,g[i].high=m;
    for(i=1;i<=k;i++)
    {
        a=read();b=read();c=read();
        g[a].p=true,g[a].low=b+1,g[a].high=c-1;
    }
    for(i=1;i<=n;i++)
        for(j=0;j<=m;j++)
            f[i][j]=INF;
    for(i=1;i<=n;i++)
    {
        for(j=t[i].x+1;j<=m+t[i].x;j++)//枚举小鸟上升
            f[i][j]=lck_min(f[i-1][j-t[i].x]+1,f[i][j-t[i].x]+1);
        for(j=m+1;j<=m+t[i].x;j++)//枚举到顶上
            f[i][m]=lck_min(f[i][m],f[i][j]); 
        for(j=1;j<=m-t[i].y;j++)//枚举下降 
            f[i][j]=lck_min(f[i][j],f[i-1][j+t[i].y]);
        for(j=1;j<g[i].low;j++)//枚举不能过柱子的情况。
            f[i][j]=INF;
        for(j=g[i].high+1;j<=m;j++)
            f[i][j]=INF;
    }
    for(i=1;i<=m;i++)
        ans=lck_min(ans,f[n][i]);
    if(ans<INF) {out(1),putchar('\n'),out(ans),putchar('\n');return 0;}
    for(i=n;i>=1;i--)
    {
        for(j=1;j<=m;j++)
            if(f[i][j]<INF) break;
        if(j<=m) break;
    }
    for(j=1;j<=i;j++)//记录小鸟最多能过多少柱子 
        if(g[j].p) ans++;
    out(0),putchar('\n'),out(ans-INF),putchar('\n');
return 0;
}

 

posted @ 2018-10-30 11:14  落笔映惆怅丶  阅读(326)  评论(0编辑  收藏  举报