洛谷-摆花-动态规划

来源:互联网 发布:酷优网络 编辑:程序博客网 时间:2024/05/16 17:49
一、题目描述
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入输出格式

输入格式:
第一行包含两个正整数n和m,中间用一个空格隔开。

第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。

输出格式:
输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。

输入输出样例
输入样例#1:
2 4
3 2
输出样例#1:
2

说明
【数据范围】

对于20%数据,有0<n≤8,0<m≤8,0≤ai≤8;

对于50%数据,有0<n≤20,0<m≤20,0≤ai≤20;

对于100%数据,有0<n≤100,0<m≤100,0≤ai≤100。

NOIP 2012 普及组 第三题


二、思路:

  这题是典型的动规题,我们用b[i][j]表示放第i种花,放j盆的放法。

  首先进行初始化,无论有多少种花,如果一盆都没有,只有一种方案总数,诶这个想想嘛(动脑子噢~)

  k是用于计算某种花放多少盆,从总盆数开始循环到(总盆数-最大盆数),如果k小于0(说明最大盆数大于总盆数)就退出循环,我们把b数组的行也就是b[i][]看成是每一种花的位置,所以我们得到状态转移方程:

     b[i][j]=b[i][j]+b[i-1][k]

       这个方程的意思是:我当前这个第i种花放的方法数+上一种花放k盆的方法数叠加

         是用背包求的方法数,所以这道题就也想用背包求方法数,没有看清题(好吧有没有看清,实在无奈了)可能更多的是对题目  的理解有偏差所导致,写成了01背包。那自然就错了,所以要看清楚题,同一种花其实是一类物品,不会对方法数造成影响。我瞬间明悟了,可惜悟错了,写的是多重背包,还是对于方法数有问题,这是一个组合的问题,而背包求得则是排列的为题,多重背包里有01背包,所以导致方法数求解有误。。需要注意
所以这道题用了三重循环100*100*100没有什么问题的时间复杂度,就将这道题过了
主要思路呢就是像动规那样一个 f 数组来表示状态,f[i][j]表示的是前 种花摆了 k 盆还剩下的空地能摆放 j 盆花。k是从1枚举到a[i]。也就是第 i 种花所有的盆数。这个其实就类似于资源分配,用这个思路去想,就可以避免我犯的错误。
代码如下,因为是三重循环没有什么思维难度。

三、代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
int n,m,temp=1000007;
int a[10010];
int f[110][110]={};
void init()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
f[0][0]=1;
}


void work()
{
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k<=a[i];k++)
{
if(j>=k)
f[i][j]=(f[i][j]+f[i-1][j-k])%temp;
}
}
}
cout<<f[n][m]%temp<<endl;
}
int main()
{
init();
work();
return 0;
}
原创粉丝点击