题外废话:

真的超级喜欢这道题


摆花【题目链接】

yy一提醒,我发现这道题和【洛谷p2089】 烤鸡有异曲同工之妙(数据更大了更容易TLE呢qwq)

SOLUTION1:(暴搜)

搜索:关于搜索就不用多介绍了吧,这里是用了dfs:dfs函数中有两个变量,rest和i分别表示还需要摆放多少盆花以及现在摆放到第几种花了,因为我们是从0开始枚举,因此如果某种花我们不选择,那就可以看做这种花选择了0盆;

几个返回条件:

1.rest==0时,记录ans++(ans是全局变量)return,不需要满足rest==0&&i=n+1(因为只要rest被枚举完了就可以了,后面的花不摆放就好啦)

2.i==n+1时,return;为什么是i=n+1呢,因为当i=n时,我们并没有枚举第n种花摆放的盆数,如果现在就返回,显然是会对结果造成很大的影响,进而影响整个结果;

3.rest<0时,return;因为此时所有m盆花已经被摆出去了,没有继续搜索的必要,直接return;

核心语句:

其实就一句话:

for(int j=;j<=a[i];j++)
dfs(rest-j,i+);

直接暴力dfs因为实际并没有改变rest和i的值,所以我们连回溯都不需回溯;

以下是完整CODE:

CODE1:

#include<bits/stdc++.h>

using namespace std;

int n,m,ans,cnt;
int a[],b[]; void dfs(int rest/*还需要摆多少盆花*/,int i/*n种花*/){
if(rest==){
ans++;ans%=;
return;
}
if(i==n+) return;
if(rest<) return;
for(int j=;j<=a[i];j++)
dfs(rest-j,i+);
return;
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
dfs(m,);
cout<<ans<<endl;
}

但是非常遗憾的是暴搜显然不是正解,成功的TLE了7个点(功成身退)

所以我们想到了记忆化搜索:

SOLUTION2:(记忆化搜索)

写暴搜的原因是因为并不会正解DP,因此只好暴搜了,然后又知道暴搜妥妥的TLE,所以在暴搜代码完成之后,改成了记忆化:

大致思路还是没有变,但dfs从没有返回值变成了带有返回值的dfs,当rest==0时(形成一种摆花条件时)return 1;否则return 0(对于最小子问题);对于每一次定义一个ans(当然也可以开全局然后每次重新赋值),枚举所有的摆花盆数,ans+=dfs(rest-j,i+1)[意思是对于某种花枚举所有可能的摆放盆数,统计剩余的空位置的总方案数,表示某种花摆j盆的总方案数(可能有点不对是非常绕)],记忆化数组b[i][rest]表示第i种花摆放前剩余rest个空位置(没有摆花)剩余rest个位置摆花的方案数,当我们已经计算过这个方案数以后,就可以直接拿来用而不是总是递归炸掉了。所以加一句

if(b[i][rest]) return b[i][rest];

如何计算b[i][rest]以及每一步的ans:

其实楼上两个东西是一回事,b[i][rest]=ans;

下面来看如何计算ans:首先枚举第i种花所有摆放盆数(0~a[i]),然后dfs(rest-j,i+1),不断将求得的值加到ans里,(ans记录的是当前要摆第i种花,此时还剩rest(第i种花还没摆)个位置时所有摆花的方案数)不要忘记取mod;

最后不要忘记return ans;

CODE2:

#include<bits/stdc++.h>

using namespace std;

long long n,m,cnt;
long long a[],b[][];
const int mod=; long long dfs(long long rest/*还需要摆多少盆花*/,long long i/*摆放n种花*/){
if(rest==)
return ;
if(i==n+) return ;
if(rest<) return ;
if(b[i][rest]) return b[i][rest];
int ans=;
for(int j=;j<=a[i];j++){
if(rest-j<) break;
ans=(ans+dfs(rest-j,i+))%mod;
}
b[i][rest]=ans;
return ans;
} int main(){
scanf("%lld%lld",&n,&m);
for(int i=;i<=n;i++)
scanf("%lld",&a[i]);
cout<<dfs(m,)%mod<<endl;
}

悄咪咪的粘上记忆化搜索的模板:(来自oi-wiki)

int g[MAXN];
int f(传入数值) {
if (g[规模] != 无效数值) return g[规模];
if (终止条件) return 最小子问题解;
g[规模] = f(缩小规模);
return g[规模];
}
int main() {
... memset(g, 无效数值, sizeof(g));
...
}

SOLUTION3:(正解-动态规划)

q姓神仙的题解【题解】

定义二维数组f[i][j]表示摆放i种花共j盆的最大方案数,初始状态是:f[i][0]=1;(因为不管是哪种花,只要不摆放,方案数均为1)这里虽然是二位数组,但DP时需要三重循环第一重循环i表示摆放i种花,第二重循环j表示这i种花共摆放多少盆(显然是1~m),第三重循环k,表示的是这种花摆放的盆数,(从0盆到a[i]盆),这里的第三层循环要从j到j-a[i]进行枚举转移方程就是f[i][j]+=f[i-1][k]%mod:

啥意思:

因为前i种花一共摆放j盆,那么假设第i种花摆放k1(k1∈(0,a[k1])盆,那么前面的i-1种花就摆放j-k1盆(所以第三层循环枚举的是前i-1种花摆放的方案数),那么所有的方案数相加就是摆放i种花j盆的最大方案数;

最后的答案就是f[n][m]%mod;(最后要%mod防止超出答案)

CODE3:

#include<bits/stdc++.h>

using namespace std;

int n,m;
int a[],f[][];
const int mod=; int main(){
cin>>n>>m;
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
for(int i=;i<=n;i++) f[i][]=;
for(int i=;i<=n;i++)//have n flower
for(int j=;j<=m;j++)//set out how many flower in total
for(int k=j;k>=j-a[i];k--) {//each flower set out how many
if(k<)break;
f[i][j]+=f[i-][k]%mod;
}
cout<<f[n][m]%mod;
}

真.end-

【洛谷p1077】摆花的更多相关文章

  1. 洛谷P1077 摆花(背包dp)

    P1077 摆花 题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能 ...

  2. 洛谷 P1077 摆花

    题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...

  3. 洛谷P1077 摆花

    题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...

  4. 洛谷—— P1077 摆花

    https://www.luogu.org/problem/show?pid=1077 题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客 ...

  5. 洛谷P1077 摆花——题解

    题目传送 题目大意:有按顺序放的n种花,相同种类的花放一起,每种花最多放ai盆,共放了m盆花,求放花方案数. 求方案个数一般有以下思路:1.搜索:2.递推/动态规划:3.贪心:4.分治... 玄学估计 ...

  6. 洛谷 P1077 摆花 (背包DP)

    题意:有\(n\)种花,每种花有\(a_i\)盆,现在要摆\(m\)盆花,花的种类从\([1,n]\)有序排放,问有多少种方案数. 题解:这题可以借用01背包的思路,感觉更好想一点,我们首先枚举\(n ...

  7. 洛谷P1077 [NOIP2012普及组]摆花 [2017年四月计划 动态规划14]

    P1077 摆花 题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能 ...

  8. 题解:洛谷P1357 花园

    题解:洛谷P1357 花园 Description 小 L 有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为 \(1∼n\).花园 \(1\) 和 \(n\) 是相邻的. 他的环形花园每天都会换 ...

  9. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

随机推荐

  1. pymysql基本操作

    https://www.cnblogs.com/woider/p/5926744.html https://www.runoob.com/python3/python3-mysql.html 注意: ...

  2. Django【第22篇】:基于Ajax实现的登录

    基于ajax实现的登录 一.需要知道的新知识点 1.刷新验证码.给src属性加一个?号.加个?会重新去请求 //#给验证码刷新 $(".vialdCode_img").click( ...

  3. js学习之BOM和DOM

    1. 浏览器的原理 1.1 浏览器的多线程 (1)  解析js引擎线程 (2)  UI渲染线程 (3)  事件发起线程 (4)  发起请求的线程 (5)  定时器的线程 1.2 同步异步 (1)  前 ...

  4. 【04】Python 深拷贝浅拷贝 函数 递归 集合

    1 深拷贝浅拷贝 1.1 a==b与a is b的区别 a == b    比较两个对象的内容是否相等(可以是不同内存空间) a is b  比较a与b是否指向同一个内存地址,也就是a与b的id是否相 ...

  5. css3 宽度百分比减去固定宽度 无效问题

    一定要注意中间横线的间距才有效果 正确 width: calc(50% - 10px); 错误 width:calc(50%-10px);

  6. LeetCode--075--颜色分类(python)

    给定一个包含红色.白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色.白色.蓝色顺序排列. 此题中,我们使用整数 0. 1 和 2 分别表示红色.白色和蓝色. ...

  7. 超赞的Linux软件分享(持续更新)

    开发 Android studio - Android 的官方 IDE:Android Studio 提供在各种类型的安卓设备上构建应用最快的工具. Aptana - Aptana Studio 利用 ...

  8. 纯CSS写的各种小三角和小箭头

    头朝下的小三角 width:0; height:0; border:50px solid transparent; //所有border都是透明的, border-top-color:black; / ...

  9. [ethereum源码分析](1) dubug环境搭建

    前言 因为最近云小哥哥换了一份工作,新公司比较忙,所以一直没有更新新的博客.云小哥哥新的公司是做区块链的,最近在学习区块链相关的东西(也算是乘坐上了区块链这艘大船).本博客是记录我搭建ethereum ...

  10. 大数据笔记(六)——HDFS的底层原理:JAVA动态代理和RPC

    一.Java的动态代理对象 实现代码如下: 1.接口类MyService package hdfs.proxy; public interface MyService { public void me ...