题外废话:

真的超级喜欢这道题


摆花【题目链接】

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. 【Luogu5293】[HNOI2019] 白兔之舞

    题目链接 题目描述 略 Sol 考场上暴力 \(O(L)\) 50分真良心. 简单的推一下式子,对于一个 t 来说,答案就是: \[\sum_{i=0}^{L} [k|(i-t)] {L\choose ...

  2. java:集合输出之Iterator和ListIterator二

    java:集合输出之Iterator和ListIterator二 ListIterator是Iterator的子接口,Iterator的最大特点是,能向前,或向后迭代.如果现在要想双向输出的话,则只能 ...

  3. hihocode 1584 : Bounce (找规律)(2017 北京网络赛G)

    题目链接 比赛时随便找了个规律,然后队友过了.不过那个规律具体细节还挺烦的.刚刚偶然看到Q巨在群里提到的他的一个思路,妙啊,很好理解,而且公式写起来也容易.OrzQ巨 #include<bits ...

  4. 【leetcode】1104. Path In Zigzag Labelled Binary Tree

    题目如下: In an infinite binary tree where every node has two children, the nodes are labelled in row or ...

  5. 【学习心得】Link-cut Tree

    Link-cut Tree是一种支持改变树(森林)的形态(link和cut),同时维护树的路径上节点信息的数据结构.lct通过splay来维护每次的perferred path,说白了就是一个动态的树 ...

  6. 正则表达式小结,数据预处理中常用的shell命令

    数据预处理中,这部分命令非常有用. 不需要编写代码,直接通过shell脚本通常就能修改文件格式.有时候sed和awk联合几乎能实现所有功能. 管道命令 | 重定向命令>,2>,>&g ...

  7. Spring Boot 异步方法的调用

    Spring Boot 异步方法的调用 参考资料: 1.Spring Boot中使用@Async实现异步调用 使用方法 两个步骤: 1.开启配置 @EnableAsync,这一步特别容易忘记,导致测试 ...

  8. IDEA简单破解激活操作流程(我在用的)

    其实简单的,你需要下一个包,将他放入你的IDEA安装目录的bin下,如下下图 下载地址:https://pan.baidu.com/s/1aJDefDGmfYGrkcJCpZYccA 看到红线的地方了 ...

  9. 深入探究JVM(1) - Java的内存区域解析

    http://blog.csdn.net/sczyh22/article/details/46652901<br>Java 虚拟机在执行Java程序的时候会把它管理的内存区域划为几部分,这 ...

  10. How to call javascript function on page load in asp.net

    How to call javascript function on page load in asp.net 解答1,使用RegisterStartupScript来运行 需要注意的是,下面的dem ...