DP刷题

来源:互联网 发布:软件研发部 考核指标 编辑:程序博客网 时间:2024/05/21 16:58

DP刷题!

序言

     这次NOIP PJ我是100+100+95+10的成绩,一等可以,但是GDKOI名额面对学校的一堆大佬我就不行了(付费玩家啊啊啊啊啊),最后一题的DP我写挂了,这是为什么我全校第五的原因,所以我特地写下此博客,来督促自己刷DP题目
     不断更新我做的题,但是题解是不存在的,只会有心得

  • DP刷题
  • 序言
  • 普及-
    • USACO07DEC手链Charm Bracelet
    • USACO09OCTBessie的体重问题Bessies We
    • 总分 Score Inflation
    • 砝码称重
    • USACO08DEC干草出售Hay For Sale
    • 最大子段和
    • L国的战斗之间谍
    • NASA的食物计划
  • 普及
    • 精卫填海
    • 球迷购票问题
    • 跨河River Crossing

普及-

[USACO07DEC]手链Charm Bracelet

原题链接

#include<iostream>#include<cstdio>using namespace std;int value[10001];int pay[10001];int totitem,maxweight;int dp[20001];int main(){    scanf("%d%d",&totitem,&maxweight);    for(int i=1;i<=totitem;++i)    {        scanf("%d%d",&pay[i],&value[i]);    }    for(int i=1;i<=totitem;++i)    {        for(int j=maxweight;j>=pay[i];--j)        {            dp[j]=max(dp[j],dp[j-pay[i]]+value[i]);        }    }    printf("%d\n",dp[maxweight]);    return 0;}

     主要是printf("%d\n",dp[maxweight]);就可以了,不用扫一遍DP数组,第一次提交时出了错。

[USACO09OCT]Bessie的体重问题Bessie’s We…

原题链接

#include<iostream>#include<cstdio>using namespace std;int value[10001];int pay[10001];int totitem,maxweight;int dp[60001],x;int main(){    scanf("%d%d",&maxweight,&totitem);    for(int i=1;i<=totitem;++i)    {        scanf("%d",&x);        pay[i]=value[i]=x;    }    for(int i=1;i<=totitem;++i)    {        for(int j=maxweight;j>=pay[i];--j)        {            dp[j]=max(dp[j],dp[j-pay[i]]+value[i]);        }    }    printf("%d\n",dp[maxweight]);    return 0;}

     和上一题差不多,但是空间限制dp[60001]要注意

总分 Score Inflation

原题链接

#include<iostream>#include<cstdio>using namespace std;int value[10001];int pay[10001];int totitem,maxweight;int dp[20001];int main(){    scanf("%d%d",&maxweight,&totitem);    for(int i=1;i<=totitem;++i)    {        scanf("%d%d",&value[i],&pay[i]);    }    for(int i=1;i<=totitem;++i)    {        for(int j=pay[i];j<=maxweight;++j)        {            dp[j]=max(dp[j],dp[j-pay[i]]+value[i]);        }    }    printf("%d\n",dp[maxweight]);    return 0;}

     题目绕了半天,原来是一个完全背包

砝码称重

原题链接

#include<iostream>#include<cstdio>using namespace std;bool have[1001];bool tmp[1001];int totweight;int kindhave[7];int w[7]={0,1,2,3,5,10,20};void copyx(bool a[],bool b[]){    for(int i=0;i<=totweight;++i)    {        b[i]=a[i];    }}int main(){    int i,k,j;    for(i=1;i<=6;++i)    {        scanf("%d",&kindhave[i]);        totweight=totweight+kindhave[i]*w[i];    }    tmp[0]=1;    have[0]=1;    for(i=1;i<=6;++i)    {        copyx(have,tmp);        for(j=0;j<=totweight;++j)        {            if(have[j]==1)            {                for(k=1;k<=kindhave[i];++k)                {                    tmp[j+w[i]*k]=1;                }            }        }        copyx(tmp,have);    }    int ans=0;    for(int i=1;i<=totweight;++i) ans+=have[i];    cout<<"Total="<<ans<<endl;    return 0;}

     我的妈,低级错误,把copy打错了,要避免…

[USACO08DEC]干草出售Hay For Sale

原题链接

#include<iostream>#include<cstdio>#include<climits>using namespace std;int value[10001];int totitem,maxweight,judge,minn=INT_MAX,maxx=INT_MIN;bool dp[50001];int main(){    scanf("%d%d",&maxweight,&totitem);    for(int i=1;i<=totitem;++i)    {        scanf("%d",&value[i]);    }    dp[0]=true;    int maxx=0;    for(int i=1;i<=totitem;++i)    {        for(int j=maxweight;j>=value[i];--j)        {            if(dp[j-value[i]]==true)            {                dp[j]=true;                maxx=max(j,maxx);                if(maxx==maxweight)                {                    printf("%d\n",maxx);                    return 0;                }            }        }    }    printf("%d\n",maxx);    return 0;}

     主要问题是n<=5000,但是随便加了一个优化就AC了……

最大子段和

原题链接

#include<iostream>#include<cstdio>#include<climits>using namespace std;int ans;int nowtot;int totnum,x;int main(){    ans=INT_MIN;    nowtot=0;    scanf("%d",&totnum);    for(int i=1;i<=totnum;++i)    {        scanf("%d",&x);        nowtot+=x;        ans=max(nowtot,ans);        if(nowtot<0) nowtot=0;    }    printf("%d\n",ans);    return 0;}

     用贪心的“DP”23333,好吧学长曾经说过贪心都可以用DP代替

L国的战斗之间谍

原题链接

#include<iostream>#include<cstdio>#include<climits>using namespace std;int totpeople,maxpay,maxmoney;int filehave[101],money[101],pay[101];int dp[1001][1001];int main(){    scanf("%d%d%d",&totpeople,&maxpay,&maxmoney);    for(int i=1;i<=totpeople;++i)    {        scanf("%d%d%d",&filehave[i],&pay[i],&money[i]);    }    for(int k=1;k<=totpeople;++k)    {        for(int i=maxpay;i>=pay[k];--i)        {            for(int j=maxmoney;j>=money[k];--j)            {                dp[i][j]=max(dp[i][j],dp[i-pay[k]][j-money[k]]+filehave[k]);            }        }    }    printf("%d\n",dp[maxpay][maxmoney]);    return 0;}

     一个打着DP名号的DFS,但是双重背包很明显才是出题者的考点

NASA的食物计划

原题链接

#include<iostream>#include<cstdio>#include<climits>using namespace std;int totitem,maxvolume,maxweight;int weight[151],volume[151],value[151];int dp[1401][1401];int main(){    int i,j,k;    scanf("%d%d%d",&maxvolume,&maxweight,&totitem);    for(i=1;i<=totitem;++i)    {        scanf("%d%d%d",&volume[i],&weight[i],&value[i]);    }    for(i=1;i<=totitem;++i)    {        for(j=maxweight;j>=weight[i];--j)        {            for(k=maxvolume;k>=volume[i];--k)            {                dp[j][k]=max(dp[j][k],dp[j-weight[i]][k-volume[i]]+value[i]);            }        }    }    printf("%d\n",dp[maxweight][maxvolume]);    return 0;}

     没什么…

普及

精卫填海

原题链接

#include<iostream>#include<cstdio>#include<cstring>using namespace std;int totstone,needvolume,power;int dp[60001];int main(){    int thisvolume,thispower;    int i,j,k;    scanf("%d%d%d",&needvolume,&totstone,&power);    for(i=1;i<=totstone;++i)    {        scanf("%d%d",&thisvolume,&thispower);        for(j=power;j>=thispower;--j)        {            dp[j]=max(dp[j],dp[j-thispower]+thisvolume);        }    }    for(j=0;j<=power;++j)    {        if(dp[j]>=needvolume)        {            printf("%d\n",power-j);            return 0;        }    }    printf("Impossible\n");    return 0;}

     开始步入普及难度的题了,这里要巧妙的【划】用体力来做DP,不然会爆空间

球迷购票问题

原题链接

#include<iostream>#include<cstdio>#include<cstring>using namespace std;long long dp[41][21];int totpeople;int main(){    scanf("%d",&totpeople);    int i,j;    dp[0][0]=1;    for(i=1;i<=totpeople*2;++i)    {        for(j=0;j<=totpeople and j<=i;++j)        {            if(j-1>=0)            {                dp[i][j]+=dp[i-1][j-1];//pick 50            }            if(i-1>=j+1)            {                dp[i][j]+=dp[i-1][j+1];//pick 100            }        }    }    printf("%lld\n",dp[totpeople*2][0]);    return 0;}

     主要是确定DP的特判有点难,其他就挺简单的

跨河River Crossing

原题链接

#include<iostream>#include<cstdio>#include<climits>#define INFF INT_MAX/2using namespace std;int dp[2501];int t[2501];int totcow,needtime;int main(){    scanf("%d%d",&totcow,&needtime);    for(int i=1;i<=totcow;++i)    {        scanf("%d",&t[i]);        t[i]+=t[i-1];    }    for(int i=1;i<=totcow;++i)    {        t[i]+=2*needtime;    }    for(int i=1;i<=totcow;++i)    {    dp[i]=t[i];        for(int j=i-1;j>=1;--j)        {            dp[i]=min(dp[i],dp[j]+t[i-j]);        }    }    printf("%d\n",dp[totcow]-needtime);    return 0;}

     花的时间这么久的原因是因为把t[i]+=2*needtime;直接写到输入中去了

原创粉丝点击