NOIP 2015 飞扬的小鸟

100 篇文章 0 订阅
57 篇文章 0 订阅

评测传送

这是一道很好的dp题。
30分的搜索;
70分的裸dp;
100分的复杂度压缩。
需要注意的问题是H数组要初始化。我的代码一开始在没有到达终点而且没有飞过一颗柱子时是没有输出的,一开始在luogu,vijos上都过了,在uoj上检查出了这个小bug,已改。

看了了这位大佬的博客,在此表示感谢和膜拜。
30分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<queue>
#define LL long long
using namespace std;
const int N=10009;
const int inf=2e9;
int n,m,k;
int X[N],Y[N];
int H[N],L[N];
bool e[N];
int ans=inf;
void dfs(int h,int x,int step)
{
    if(x==n+1) 
    {
        ans=min(ans,step);
        return;
    }
    if(h<=0) return;
    if(e[x]&&(h<=L[x]||h>=H[x])) return;
    for(int i=1;i<=3;i++)
    {
        dfs(min(h+i*X[x],m),x+1,step+i);
    }
    dfs(h-Y[x],x+1,step);
}
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<=k;i++)
    {
        int p,l,h;
        scanf("%d%d%d",&p,&l,&h);
        H[p]=h,L[p]=l;e[p]=1;
    }
    for(int i=1;i<=m;i++) dfs(i,0,0);
    if(ans!=inf) printf("1\n%d",ans);
    else printf("0%d\n",5);
    return 0;
}

70分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<queue>
#define LL long long
using namespace std;
const int N=10009;
const int M=1009;
int n,m,k;
int X[N],Y[N];
int H[N],L[N];
int e[N];
int f[N][M],ans;
int main()
{
    memset(f,127/3,sizeof(f));
    memset(L,0,sizeof(L));
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<=n;i++) H[i]=m+1;
    for(int i=0;i<n;i++) scanf("%d%d",&X[i],&Y[i]);
    for(int i=1;i<=k;i++)
    {
        int p,l,h;
        scanf("%d%d%d",&p,&l,&h);
        H[p]=h,L[p]=l;e[p]=1;
    }
    for(int i=1;i<=n;i++) e[i]+=e[i-1];
    for(int i=1;i<=m;i++) f[0][i]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=L[i]+1;j<H[i];j++)
        {
            for(int p=1;j-p*X[i-1]>0;p++)
             if(j-p*X[i-1]>L[i-1]&&j-p*X[i-1]<H[i-1])
                f[i][j]=min(f[i][j],f[i-1][j-p*X[i-1]]+p);
            if(j+Y[i-1]<H[i-1]&&j+Y[i-1]>L[i-1])f[i][j]=min(f[i][j],f[i-1][j+Y[i-1]]);
            if(j==m)
            for(int p=L[i-1]+1;p<H[i-1];p++)
            f[i][j]=min(f[i][j],f[i-1][p]+(j-p)/X[i-1]+1);
        }
    }
    ans=f[0][0];
    for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
    if(ans!=f[0][0]) printf("1\n%d",ans);
    else
    {
        for(int i=n;i>=1;i--)
         for(int j=1;j<=m;j++)
         {
            if(f[i][j]!=f[0][0])
            {
                printf("0\n%d",e[i]);
                return 0;
            }
         }
    }
    return 0;
}

100分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<queue>
#define LL long long
using namespace std;
const int N=10009;
const int M=1009;
int n,m,k;
int X[N],Y[N];
int H[N],L[N];
int e[N];
int f[N][M],ans;
int main()
{
    memset(f,127/3,sizeof(f));
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<=n;i++) H[i]=m+1;
    for(int i=0;i<n;i++) scanf("%d%d",&X[i],&Y[i]);
    for(int i=1;i<=k;i++)
    {
        int p,l,h;
        scanf("%d%d%d",&p,&l,&h);
        H[p]=h,L[p]=l;e[p]=1;
    }
    for(int i=1;i<=n;i++) e[i]+=e[i-1];
    for(int i=1;i<=m;i++) f[0][i]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(j-X[i-1]>0) f[i][j]=f[i][j-X[i-1]]+1;//优化 
            if(j-X[i-1]>L[i-1]&&j-X[i-1]<H[i-1])
            f[i][j]=min(f[i][j],f[i-1][j-X[i-1]]+1);
            if(j==m)
            {
                for(int p=L[i-1]+1;p<H[i-1];p++) 
                 f[i][j]=min(f[i][j],f[i-1][p]+(j-p)/X[i-1]+1);
            }
        }
        for(int j=L[i]+1;j<H[i];j++) 
        if(j+Y[i-1]<H[i-1]&&j+Y[i-1]>L[i-1]) f[i][j]=min(f[i-1][j+Y[i-1]],f[i][j]);

    }
    ans=f[0][0];
    for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
    if(ans!=f[0][0]) {printf("1\n%d",ans);return 0;} 
    else
    {
        for(int i=n;i>=1;i--)
         for(int j=L[i]+1;j<H[i];j++)
         {
            if(f[i][j]<f[0][0])
            {
                printf("0\n%d",e[i]);
                return 0;
            }
         }
    }
    printf("0\n0");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值