P1941 [NOIP2014 提高组] 飞扬的小鸟

每一个x横坐标 可以点击多次 效果叠加 但哟避开 障碍

 》状态更新-> dp  dp[x][y][p] 当前坐标 x y 上一个坐标 转移过来 不点 0/点击 1

  1.p=1 dp[x][y][1]=min(dp[x-1][y-up[i-1]][0/1],dp[x][ y-up[x-1] ][1])

  2.p=0 dp[x][y][0]=min(dp[x-1][y+down[x-1]][0/1],dp[x][y][0])

优化 [p]->很明显每次选取都是在p=0or1p=0or1中选取最小值,那么可以滚动数组去掉p数组,上状态转移方程其他不变。

  memset(dp,0x3f)  dp[0][1~n]=0(从>=1出发) dp[x][1~low]=inf,dp[x][up~n]=inf

若过不了  int i,j; for(i=n;i>=1;i--) { for(j=1;j<=m;++j) { if(f[i][j]<f[0][0]) break; } if(j<=m) break; } ans=0; for(int j=1;j<=i;++j) { if(e[j]) ans++; } printf("0\n%d\n",ans);

》up 完全背包 down 0/1背包

》[x]只与上一个状态有关 i%2 i%2^1(i-1%2) 

 

#include<bits/stdc++.h>
using namespace std;
#define int int
#define gc(a) a=getchar()
#define pc(a) putchar(a)
int read(){
    char c;int x=0;bool flag=0;c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48),c=getchar();}
    return flag?-x:x;
}
void pr(int x){
    if(x<0){x=-x;putchar('-');}
    if(x>9) pr(x/10);
    putchar(x%10+48);
}
//-------快读------
#define inf 0x3f3f3f3f
const int maxn=10005;
const int maxm=10005;
struct node
{
    int id,h,l;
    bool operator <(const node &a) const
    {
        return id<a.id;
    }
}o[maxn];
int x[maxn],y[maxn],dp[2][maxm],n,m,k,cnt=1,ans;
int main()
{
    memset(dp,inf,sizeof(dp));//两个被遗忘的初始化之一qwq
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;i++)
    x[i]=read(),y[i]=read();
    for(int i=1;i<=k;i++)
    o[i].id=read(),o[i].l=read(),o[i].h=read();
    sort(o+1,o+k+1);//管道id排序!
    for(int i=1;i<=m;i++)
    dp[0][i]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)//注意要初始化!
        dp[i%2][j]=inf;
        for(int j=x[i]+1;j<=x[i]+m;j++)//p=1,完全背包
        dp[i%2][j]=min(dp[i%2^1][j-x[i]]+1,dp[i%2][j-x[i]]+1);
        for(int j=m+1;j<=x[i]+m;j++)//比m大的都是m
        dp[i%2][m]=min(dp[i%2][m],dp[i%2][j]);
        for(int j=1;j<=m-y[i];j++)//p=0,01背包
        dp[i%2][j]=min(dp[i%2][j],dp[i%2^1][j+y[i]]);
        if(i==o[cnt].id)//如果这个地方有管道
        {
            ans=inf;//主要每次都要初始化一次!
            for(int j=0;j<=o[cnt].l;j++)
            dp[i%2][j]=inf;
            for(int j=o[cnt].h;j<=m;j++)
            dp[i%2][j]=inf;
            for(int j=1;j<=m;j++)//寻找是否可以通过
            ans=min(dp[i%2][j],ans);
            if(ans==inf)
            {
                pr(0);putchar('\n');pr(cnt-1);return 0;
            }
            cnt++;
        }
    }
    ans=inf;//注意要初始化!
    for(int j=1;j<=m;j++)
    ans=min(dp[n%2][j],ans);
    pr(1);putchar('\n');pr(ans);
    return 0;
}
/*
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=10000+10;
const int maxm=2000+10;
int n,m,p;
int x[maxn],y[maxn];   //i位置,上升x[i],下降y[i] 
int low[maxn],high[maxn];   //i位置能通过的范围是low[i]-high[i] 
int f[maxn][maxm];   //到(i,j)的最少点击次数 
bool e[maxn];    //e[i]表示i位置有没有管道 
int main() {
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1; i<=n; ++i) scanf("%d%d",&x[i],&y[i]);
    for(int i=1; i<=n; ++i) {
        low[i]=1;
        high[i]=m;
    }
    int a,b,c;
    for(int i=1; i<=p; ++i) {
        scanf("%d%d%d",&a,&b,&c);
        e[a]=1;
        low[a]=b+1;
        high[a]=c-1;
    }
    memset(f,0x3f,sizeof(f));
    for(int i=1; i<=m; ++i) f[0][i]=0;
    for(int i=1; i<=n; ++i) {
        for(int j=x[i]+1; j<=m+x[i]; ++j)
            f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);
        for(int j=m+1; j<=m+x[i]; ++j)
            f[i][m]=min(f[i][m],f[i][j]);
        for(int j=1; j<=m-y[i]; ++j)
            f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
        for(int j=1; j<low[i]; ++j)
            f[i][j]=f[0][0];   //不能通过(INF) 
        for(int j=high[i]+1; j<=m; ++j)
            f[i][j]=f[0][0];   //不能通过(INF)
    }
    int ans=f[0][0];
    for(int j=1;j<=m;++j) {
        ans=min(ans,f[n][j]);
    }
    if(ans<f[0][0]) printf("1\n%d\n",ans);
    else{
        int i,j;
        for(i=n;i>=1;i--) {
            for(j=1;j<=m;++j) {
                if(f[i][j]<f[0][0]) break;
            }
            if(j<=m) break;
        }
        ans=0;
        for(int j=1;j<=i;++j) {
            if(e[j]) ans++;
        }
        printf("0\n%d\n",ans);
    }
    return 0;
}
*/

 

posted @ 2023-09-09 16:12  JMXZ  阅读(21)  评论(0)    收藏  举报