洛谷 P2089. 烤鸭--暴力枚举与搜索
烤鸡
题目背景
猪猪 Hanke 得到了一只鸡。
题目描述
猪猪 Hanke 特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke 吃鸡很特别,为什么特别呢?因为他有 \(10\) 种配料(芥末、孜然等),每种配料可以放 \(1\) 到 \(3\) 克,任意烤鸡的美味程度为所有配料质量之和。
现在, Hanke 想要知道,如果给你一个美味程度 \(n\) ,请输出这 \(10\) 种配料的所有搭配方案。
输入格式
一个正整数 \(n\),表示美味程度。
输出格式
第一行,方案总数。
第二行至结束,\(10\) 个数,表示每种配料所放的质量,按字典序排列。
如果没有符合要求的方法,就只要在第一行输出一个 \(0\)。
样例 #1
样例输入 #1
11
样例输出 #1
10
1 1 1 1 1 1 1 1 1 2
1 1 1 1 1 1 1 1 2 1
1 1 1 1 1 1 1 2 1 1
1 1 1 1 1 1 2 1 1 1
1 1 1 1 1 2 1 1 1 1
1 1 1 1 2 1 1 1 1 1
1 1 1 2 1 1 1 1 1 1
1 1 2 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1 1
提示
对于 \(100\%\) 的数据,\(n \leq 5000\)。
题解
本来想到搜索的解法了 但由于递归还不太熟练 于是放弃了(其实搜索是正解)
感觉不能冷静下来仔细分析 明明只需要暴力枚举每一个数的情况 看他们加起来等不等于10就行了
但就是没有静下来思考 老想着什么简便做法 说实话就是不熟练
提供两种做法 暴力枚举 和 搜索(利用递归)
暴力
#include <bits/stdc++.h>
using namespace std;
int ans;
int x;
//一共十种配料要用到十重循环
int i, j, k, l, m, n, o, p, q, r;
int main()
{
scanf("%d", &ans);
for (int i = 1; i <= 3; i ++ )
{
for (int j = 1; j <= 3; j ++ )
{
for (int k = 1; k <= 3; k ++ )
{
for (int l = 1; l <= 3; l ++ )
{
for (int m = 1; m <= 3; m ++)
{
for (int n = 1; n <= 3; n ++ )
{
for (int o = 1; o <= 3; o ++ )
{
for (int p = 1; p <= 3; p ++ )
{
for (int q = 1; q <= 3; q ++ )
{
for (int r = 1; r <= 3; r ++ )
{
if (ans == i + j + k + l + m + n + o + p + q + r) x ++ ;
}
}
}
}
}
}
}
}
}
}
if (x) printf("%d\n", x);
else printf("0\n");
for (int i = 1; i <= 3; i ++ )
{
for (int j = 1; j <= 3; j ++ )
{
for (int k = 1; k <= 3; k ++ )
{
for (int l = 1; l <= 3; l ++ )
{
for (int m = 1; m <= 3; m ++)
{
for (int n = 1; n <= 3; n ++ )
{
for (int o = 1; o <= 3; o ++ )
{
for (int p = 1; p <= 3; p ++ )
{
for (int q = 1; q <= 3; q ++ )
{
for (int r = 1; r <= 3; r ++ )
{
if (ans == i + j + k + l + m + n + o + p + q + r)
{
printf("%d %d %d %d %d %d %d %d %d %d\n", i, j, k, l, m, n, o, p, q, r);
}
}
}
}
}
}
}
}
}
}
}
return 0;
}
搜索 阴间阴间阴间
居然写搜索debug了这么久 一直segmentation fault 找到原因了
新学了个知识
else if (a >= n) ;
这句话的作用是当满足a>=n时函数将终止执行 与 else if (a >= n) return;
等价
不加这两行本题你就没有退出递归的条件
第三种写法就是在进入递归函数那里判断一下
for (int i = 1; i <= 3; i ++ )
{
m[total] = i;
if(total <= 10)
dfs(total + 1, a + i);
}
第二个坑! 提交评测时候才发现会tle
当dfs里面你这么写判断条件if (total == 10 && a == n)
会超时!!
你必须要把它改成if (total == 10){ if(a == n) ...
或者在下面加上if(total <= 10)
所以以后写代码的时候能少用&&就少用
#include <bits/stdc++.h>
using namespace std;
const int N = 10010; //最大方案数 往大了取就行
int n;
int kind; //方案数
int f[N][20]; //存一下答案
int m[20]; //存当前已经撒上的i配料克数
void dfs(int total, int a) //total表示当前已经执行到第几个配料(从0开始) a表示一共需要多少克
{
if (total == 10)
{
if(a == n)
{
for(int i = 0; i < 10; i ++ ) f[kind][i] = m[i];
kind ++ ;
//return;
//cout << kind;
}
}
else if (a >= n) ; //这一行是必须加的 当满足条件 a >= n 时,递归将停止执行,不再进行下一次递归调用。这样可以避免无限递归,确保递归函数能够正常结束。
else //这里一定要加else 要不然就是死循环了
{
for (int i = 1; i <= 3; i ++ ) //每一个配料有三种克数选择 当时搜索没想出来就是卡在这了
{
m[total] = i;
//if(total <= 10)
dfs(total + 1, a + i);
}
}
}
int main()
{
scanf("%d", &n);
dfs(0, 0);
printf("%d\n", kind);
if (kind)
{
for (int i = 0; i < kind; i ++ )
{
for (int j = 0; j < 10; j ++ )
{
printf("%d ", f[i][j]);
}
cout << endl;
}
}
else printf("0");
return 0;
}