• 搜索入门练习题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;
    }
    
  • 相关阅读:
    jsfl 常用自定义方法
    jsfl 常用方法
    Java 跨平台原理
    JDK、JRE 和 JVM 的区别
    win10 中安装 JDK8 以及环境配置
    JDK 14 都已经发布了,Java 8 依然是我的最爱
    DOS 命令大全用法详解
    《Java程序设计基础》 第4章手记
    堆和栈的区别
    CC#JavaPython 基本数据类型比较
  • 原文地址:https://www.cnblogs.com/zifeiynoip/p/11450700.html
Copyright © 2020-2023  润新知