首页 > 代码库 > noip前的dp挣扎

noip前的dp挣扎

写了几道比较水的dp,但是也有很多问题,初始化和循环的顺序等问题、还有最大的问题:动规方程。。。

 

CODEVS1253 超级市场

题目描述 Description

某人喜欢按照自己的规则去市场买菜,他每天都列一个买菜的清单,自由市场的菜码放也有一个顺序,该人有一个特点,就是按顺序买菜,从不走回头路,当然,她希望能花最好的钱买到所有的菜,你能帮帮他吗?

 

输入输出数据如下图:

 
思路:比较简单的dp,f[i][j]表示市场上的菜单到i需购买的菜单到j所需的最少花费,若i=j,则更新这个点,否则f[i][j]=f[i-1][j]。初始化将f[i][0]=0;其他都付最大值,最后比较f[n][m]和0x7fffffff,若大于则是impossible,否则输出。
 
#include<iostream>#include<cstdio>#include<cstring>using namespace std;struct use{    int kind;    double mon;}b[100001];double f[100001][101]={0};int a[101]={0};int main(){    int i,j,n,m,k;    scanf("%d%d",&m,&n);    memset(f,127,sizeof(f));    for (i=1;i<=m;++i)      scanf("%d",&a[i]);    for (i=1;i<=n;++i)      scanf("%d%lf",&b[i].kind,&b[i].mon);    for(i=1;i<=n;++i)      f[i][0]=0;     for (i=1;i<=n;++i)      for (j=1;j<=m;++j)      {          f[i][j]=f[i-1][j];        if (b[i].kind==a[j])            f[i][j]=min(f[i][j],f[i-1][j-1]+b[i].mon);      }    if (f[n][m]>0x7fffffff) printf("Impossible\n");    else      printf("%.2f\n",f[n][m]);}
RZUC Code

 

 

CODEVS1959 拔河游戏

题目描述 Description

一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近。

 

思路:一个二维费用(bool)背包问题,一个是元素个数(相当于体积),一个是体重。先求出总重的一半和元素个数一半,进行背包。

 

#include<iostream>#include<cstdio>using namespace std;bool f[101][45001]={false};int a[101]={0};int main(){    int i,j,sum=0,n,k,q,cha,summ;    cin>>n;    if (n%2==0) k=n/2;    else k=n/2+1;    for (i=1;i<=n;++i)    {      cin>>a[i];      sum+=a[i];    }    if (summ%2==0) summ=sum/2;    else summ=sum/2+1;      for (i=0;i<=1;++i)      f[i][0]=true;    for (i=1;i<=n;++i)      for (j=summ;j>=a[i];--j)        for (q=k;q>=1;--q)        f[q][j]=f[q][j]||f[q-1][j-a[i]];    for (j=summ;j>=0;--j)      if (f[k][j])      {          cout<<min(j,sum-j)<<" "<<max(j,sum-j)<<endl;        break;      }  }
RZUC Code

 

 

CODEVS1060 搞笑世界杯

题目描述 Description

    随着世界杯小组赛的结束,法国,阿根廷等世界强队都纷纷被淘汰,让人心痛不已. 于是有

人组织了一场搞笑世界杯,将这些被淘汰的强队重新组织起来和世界杯一同比赛.你和你的朋

友欣然去购买球票.不过搞笑世界杯的球票出售方式也很特别,它们只准备了两种球票.A 类

票------免费球票 B 类票-------双倍价钱球票.购买时由工作人员通过掷硬币决定,投到正面

的买A类票, 反面的买B类票.并且由于是市场经济,主办方不可能倒贴钱,所以他们总是准备

了同样多的A类票和B类票.你和你的朋友十分幸运的排到了某场精彩比赛的最后两个位置.

这时工作人员开始通过硬币售票.不过更为幸运的是当工作人员到你们面前时他发现已无需

再掷硬币了,因为剩下的这两张票全是免费票。

 

    你和你的朋友在欣喜之余,想计算一下排在队尾的两个人同时拿到一种票的概率是多少

(包括同时拿A 类票或B类票) 假设工作人员准备了2n 张球票,其中n 张A类票,n 张B类票,并且排在队伍中的人每人必须且只能买一张球票(不管掷到的是该买A 还是该买B).

 

思路:先说一个比较坑爹的事情,读入的是2n,不是n。f[i][j]表示第i人买票时买了j张A票的概率。对于j有三种情况:

  1)j=0:f[i][j]=f[i-1][j]*0.5;   2)0<j<n:f[i][j]=(f[i-1][j]+f[i-1][j-1])*0.5;  3)j=n:f[i][j]=f[i-1][j]+f[i-1][j-1]*0.5。

初始化f[0][0]=1;输出f[n*2-2][n]*2(因为最后两张可以全是A或B);

 

#include<iostream>#include<cstdio>using namespace std;double f[3000][3000]={0};int main(){    int n,i,j;    cin>>n;    n/=2;    f[0][0]=1;    for (i=1;i<=2*n;++i)      for (j=0;j<=n;++j)      {          if (j>i) continue;          if (j==0) f[i][j]=f[i-1][j]*0.5;          else          {              if (j<n) f[i][j]=(f[i-1][j]+f[i-1][j-1])*0.5;              else f[i][j]=f[i-1][j]+f[i-1][j-1]*0.5;          }      }    printf("%.4f\n",f[n*2-2][n]*2);}
RZUC Code

 

 

CODEVS3369 膜拜

题目描述 Description

神牛有很多…当然…每个同学都有自己衷心膜拜的神牛.
某学校有两位神牛,神牛甲和神牛乙。新入学的N位同学们早已耳闻他们的神话。所以,已经衷心地膜拜其中一位了。
现在,老师要给他们分机房。
但是,要么保证整个机房都是同一位神牛的膜拜者,或者两个神牛的膜拜者人数差不超过M。
另外,现在N位同学排成一排,老师只会把连续一段的同学分进一个机房。老师想知道,至少需要多少个机房。

 
思路:预处理一下前i位置有多少个两个神牛的崇拜者(前缀和数组),然后就是dp部分了,f[i]表示分到i个人最少多少个教室,循环i和k(i-k表示最后一个教室的人数),更新f[i]的值。预处理:f[0]=0;
 
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;int f[3000]={0},sum1[3000]={0},sum2[3000]={0};int main(){    int n,m,i,j,x;    memset(f,127/3,sizeof(f));    scanf("%d%d",&n,&m);    for (i=1;i<=n;++i)    {      sum1[i]=sum1[i-1];      sum2[i]=sum2[i-1];      scanf("%d",&x);      if (x==1) ++sum1[i];      else ++sum2[i];    }    f[0]=0;    for (i=1;i<=n;++i)      for (j=0;j<i;++j)        if (abs((sum1[i]-sum1[j])-(sum2[i]-sum2[j]))<=m||           sum1[i]-sum1[j]==0||sum2[i]-sum2[j]==0)          f[i]=min(f[i],f[j]+1);    cout<<f[n]<<endl;}
RZUC Code

 

 

CODEVS

题目描述 Description

现在有n个物品(有可能相同),请您编程计算从中取k个有多少种不同的取法。

 

思路:多重背包问题,将数字作为元素,出现的次数为个数。注意选取个数时候的循环要循环到1,一开始循环到了0,结果wa了。。。作死。。。

 

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int a[31],f[31]={0},w[31]={0};int main(){    int n,k,i,j,p;    cin>>n>>k;    for (i=1;i<=n;++i)      cin>>a[i];    sort(a+1,a+n+1);    ++w[0];    ++w[w[0]];    for (i=2;i<=n;++i)    {      if (a[i]==a[i-1])        ++w[w[0]];      else      {          ++w[0];          ++w[w[0]];      }      if (w[w[0]]>k) w[w[0]]=k;    }    f[0]=1;    for (i=1;i<=w[0];++i)      for (j=k;j>=0;--j)        for (p=w[i];p>=1;--p)          if (j>=p)            f[j]=f[j]+f[j-p];    cout<<f[k]<<endl;}
RZUC Code

 

noip前的dp挣扎