搜索入门练习题3 全组合 题解

题目出处:《信息学奥赛一本通》例5.2。

题目描述

设有 \(n\) 个数的集合 \(\{1,2,...,n\}\) ,从中任意取出 \(r\) 个数进行排列 \((r \le n)\) ,试列出所有的排列。

输入格式

输入包含两个正数 \(n,r(1 \le r \le n \le 10)\)

输出格式

输出从 \(n\) 个数的集合中选出 \(r\) 个数的所有组合,每个组合方案占一行。对于每个组合,按照从小到大的顺序输出组合中的所有元素,两两之间有一个空格分隔。

样例输入

3 2

样例输出

1 2
1 3
2 3

题目分析

“全组合”这道题目和“全排列”很像。首先我们会想到的是使用搜索来解决这个问题。我们这里采用深度优先搜索(DFS)来解决这个问题。
首先我们可以看到这道题是求出 \(n\) 个数中选 \(r\) 个数的所有排列方案,所以我们开一个 ans[] 数组来存放我们当前遍历到的排列的所有方案。ans[id] 用于表示我当前排列中的第 id 个元素的值。然后我们开一个 void f(int id) 函数用于选出当前排列的第 id 个值是什么,选完第 id 个值我们再递归地去选第 id+1 个值,直到到达了边界条件—— id>r ,此时说明我已经找到了排列中的 r 个数了,输出这个方案然后回溯再去遍历看看有没有新的方案。
ans[] 数组的第 id 个位置能放数 i 当且仅当满足如下条件:

  • ans[1]ans[id-1] 中没有一个数等于 i(说明 i 之前没有放过);
  • 当 \(id>1\) 时,要确保 \(ans[id-1] < i\) (要保证排列的前一个元素小于后一个元素)。

实现代码如下:

#include<bits/stdc++.h>
using namespace std;
int n, r, ans[11];
void f(int id) {    // 用于在第id个位置放数
    if (id > r) {   // 边界条件,如果id>r,说明排列的r个数(ans[1]到ans[r])都找到了
        for (int i = 1; i <= r; i ++)
            cout << (i>1 ? " " : "") << ans[i];
        cout << endl;
        return;
    }
    for (int i = 1; i <= n; i ++) {
        if (id > 1 && i <= ans[id-1]) continue; // 确保i为我上一个放的数ans[id-1]要大
        bool flag = true;
        for (int j = 1; j < id; j ++)   // 判断是否存在ans[j]==i
            if (ans[j] == i) {
                flag = false;
                break;
            }
        if (flag) {     // 如果flag==true,说明i能放在ans[id]位置
            ans[id] = i;    // 尝试放i,再递归搜索
            f(id+1);
        }
    }
}
int main() {
    cin >> n >> r;
    f(1);
    return 0;
}

原文地址:https://www.cnblogs.com/zifeiynoip/p/11450700.html

时间: 2024-10-10 05:10:03

搜索入门练习题3 全组合 题解的相关文章

搜索入门练习题1 素数环 题解

题目出处:<信息学奥赛一本通>例5.1. 题目描述 素数环:从 \(1\) 到 \(n(2 \le n \le 20)\) 这 \(n\) 个数摆成一个环,要求相邻的两个数的和是一个素数. 输入格式 输入包含一个整数 \(n(2 \le n \le 20)\) . 输出格式 按字典序从小到大的顺序输出所有排列方案,每个排列方案占一行.每行的 \(n\) 个数之间由一个空格分隔. 样例输入 2 样例输出 1 2 2 1 问题分析 很明显,这是一道可以用搜索解决的问题,我们可以采用"回溯

搜索入门练习题2 全排列 题解

题目出处:课程=>搜索1=>题目A 题目描述 给定一个正整数 \(n\) ,按照递增顺序打印数字 \(1\) 到 \(n\) 的所有排列. 输入格式 一个整数 \(n(1 \le n \le 7)\) . 输出格式 按照递增顺序输出 \(n\) 个数的所有排列,每行代表一组排列, \(n\) 个数两两之间有一个空格分隔. 样例输入 3 样例输出 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 问题分析 这是一道搜索的题目. 我们知道搜索就是状态到状态之间的转换,其本质是

搜索入门练习题7 最高效益和 题解

题目出处:<信息学奥赛一本通>例5.6 题目描述 设有A.B.C.D.E五人从事J1.J2.J3.J4.J5五项工作,每人只能从事一项,他们的效益如下所示. ? J1 J2 J3 J4 J5 A 13 11 10 4 7 B 13 10 10 8 5 C 5 9 7 7 4 D 15 12 10 11 5 E 10 11 8 8 4 每人选择五项工作中的一项,在各种选择的组合中,找到效益最高的一组输出. 题目分析 这道题目其实就是"全排列"问题的变形题,我们可以使用深度优先

搜索入门练习题4 数的拆分 题解

题目描述 任何一个大于 \(1\) 的自然数 \(n\) ,总可以拆分成若干个小于 \(n\) 的自然数之和.当 \(n = 4\) 时,总共有 \(4\) 种拆分方法: \(4=1+1+1+1\) \(4=1+1+2\) \(4=1+3\) \(4=2+2\) 现在给你一个数 \(n(1 \le n \le 20)\) ,请按顺序输出 \(n\) 的所有拆分方案. 输入格式 输入包含一个整数 \(n(1 \le n \le 20)\) . 输出格式 输出 \(n\) 的所有拆分方案,每种方案占

搜索入门练习题5 八皇后问题 题解

题目来源:<信息学奥赛一本通>例5.4 题目描述 要在国际象棋棋盘(\(8 \times 8\) 的棋盘)中放 \(8\) 个皇后,使任意两个皇后都不能互相吃.(提示:皇后能吃同一行.同一列.同一对角线的任意棋子.) 输出格式 输出一个整数,用于表示八皇后问题的放置方案. 题目分析 首先我们用 \((x,y)\) 来表示棋盘上第 \(x\) 行第 \(y\) 列的格子的坐标. 那么,两个皇后 \((x_1,y_1)\) 和 \((x_2,y_2)\) 会互相攻击当且仅当满足如下条件之一: 在同

Python入门(目录全览)

目录 Python入门(目录全览) 第一篇 markdown编辑器 第二篇 计算机基础 第三篇 Python解释器和集成环境 第三篇 Python基础 第四篇 Python进阶 第五篇 文件处理 第六篇 函数基础 第七篇 函数进阶 第八篇 模块基础 第九篇 Python常用模块 第十篇 面向对象基础 第十一篇 面向对象进阶 第十二篇 面向对象高阶 第十三篇 网络编程 第十四篇 并发编程 第十五篇 MySQL数据库 Python入门(目录全览) 第一篇 markdown编辑器 001markdow

递归求解几类排列组合问题(二、全组合排列)

对于搜索的深度很深或深度不固定的情况,则无法用枚举的方法来设置循环嵌套的层数,这时可以考虑用递归法来完成搜索任务.递归是一种常用算法,它是搜索的另一种实现方式.如果在算法设计中采用一个函数或过程直接或间接地调用它自身来解决问题的方法,则称该方法为递归算法.递归算法必须要设计好一个或若干个确定的递归终止条件. Sample Input 3 1 2 3 Sample Output 123 132 213 231 312 321 #include<stdio.h> #include<strin

四十七 Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html 1.创建搜索自动补全字段suggest 自动补全需要用到一个字段名称为suggest类型为Completion类型的一个字段 所以我们需要用将前面的elasticsearch-dsl操作elasticsearch(搜索引擎)增加sugg

第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲-用Django实现搜索的自动补全功能 elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html 创建自动补全字段 自动补全需要用到一个字段名称为suggest类型为Completion类型的一个字段 所以我们需要用