洛谷 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;
}
posted @ 2024-04-16 16:51  MsEEi  阅读(70)  评论(0)    收藏  举报