📜  门|门 CS 1999 |第 39 题(1)

📅  最后修改于: 2023-12-03 15:42:21.039000             🧑  作者: Mango

题目描述

门|门 CS 1999 是一道经典的程序设计题目,要求设计一个程序,实现两门课程之间的选课问题。具体来说,有 n 门课程,每门课程都有 m 个选课学生,其中任意两个学生都选了不同的课程。现在需要选出 p 对课程并且满足两个条件:1)每个选课学生都选了恰好一对课程;2)从所有可行的选课方案中选择 p 对课程,要求这 p 对课程的交集为空集,即这些课程之间不存在公共选课学生。设计一个程序,输出满足条件的选课方案。

输入格式

程序的输入格式如下:

第一行包含三个整数 n,m,p,表示课程数、每门课程选课学生数、要求的选课方案对数。

接下来 n 行,每行包含 m 个整数,用空格分隔,表示每门课程的选课学生编号。

输出格式

程序的输出格式如下:

输出 p 行,每行包括两个整数,表示一对选课方案,用空格分隔。

样例输入

3 4 2
1 2 3 4
4 3 2 1
1 3 2 4

样例输出

1 3
2 3

解题思路

这道题目要求我们输出所有符合要求的选课方案,需要用到深度优先搜索(DFS)算法。DFS 是一种常见的搜索算法,用于在一些非叶节点的分支下,沿着深度方向搜索更多的节点。对于本题,在搜索过程中,我们需要用一个 visited 数组来记录每个学生是否已被分配到某对选课方案中,以防止重复选取。

具体操作如下:

  • 首先,我们需要先对每门课程选课学生进行编号,得到一个二维数组 arr,表示每门课程的选课学生编号。
  • 然后,我们定义一个 dfs 函数,用于进行深度优先搜索。dfs 函数的输入参数包括要选取的课程对数、已经选取的课程对、以及选取课程的起止位置。
  • 在 dfs 函数中,我们需要遍历每一对选课方案(也就是遍历 arr[i] 和 arr[j],i 和 j 分别为选取课程的起止位置)。在遍历过程中,我们需要注意以下几点:
    • 首先,需要对 visited 数组进行更新,防止重复选取。
    • 其次,要判断当前选取的两门课程是否重叠,如果重叠,则需要选择其他的课程。
    • 最后,要判断已经选取的课程对数是否已经达到了要求的目标,如果已经达到目标,则将结果存储到 vector 中,并返回。

参考代码

#include<bits/stdc++.h>
using namespace std;
vector<pair<int, int>> res; // 存放结果
vector<bool> visited(15, false); // 记录每个学生是否已被选
vector<vector<int>> arr; // 存储每门课程的选课学生编号
void dfs(int n, int m, int p, int cnt, int s, int e) {
    if (cnt == p) { // 达到目标
        for (auto r : res) { // 输出结果
            cout << r.first << " " << r.second << "\n";
        } 
        return; 
    }
    if (s == n) return; //边界
    if (e >= m) { // 下一门课
        dfs(n, m, p, cnt, s + 1, s + 2); 
        return;
    }
    for (int i = s; i < n; ++i) {
        for (int j = e; j < m; ++j) {
            if (visited[arr[i][j]]) continue; // 已被选
            bool flag = true; // 是否重叠
            for (auto r : res) {
                if ((r.first == i + 1 && r.second == (j / 2) + 1) || (r.second == i + 1 && r.first == (j / 2) + 1))
                    flag = false;
            }
            if (!flag) continue;
            visited[arr[i][j]] = true; // 标记为已选
            res.push_back(make_pair(i + 1, (j / 2) + 1)); // 加入结果
            dfs(n, m, p, cnt + 1, s, j + 2);
            res.pop_back(); // 回溯
            visited[arr[i][j]] = false; // 标记为未选
        }
    }
}
int main() {
    int n, m, p;
    cin >> n >> m >> p;
    arr.resize(n, vector<int>(m));
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            cin >> arr[i][j];
    dfs(n, m, p, 0, 0, 1);
    return 0;
}