洛谷 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  阅读(22)  评论(0)    收藏  举报