机试题——防止重复测试的穿戴设备分配问题

题目描述

终端部门为了对穿戴设备进行交叉测试,目前有 ( n ) 名员工投入测试,人员从 1 到 ( n ) 依次编号。为了充分测试和暴露问题,要求任何两个以前戴过同一穿戴设备的人不能再次测同一设备。下面会给出测试投入的人数和测过同一台设备的人员编号,请按照此关系,计算这次至少需要几台穿戴设备供测试。

输入描述

第一行,一个整数 ( n )(1 < n < 100),表示参加测试的人数,人员从 1 到 ( n ) 依次编号。

第二行,一个整数 ( m ),表示接下来有 ( m ) 行数据,1 <= m <= C(n, 2)。

以下 ( m ) 行每行的格式为:两个整数 ( a ),( b ),分别表示员工 ( a ) 和员工 ( b ),用空格分开(1 <= a, b <= n),表示员工 ( a ) 与员工 ( b ) 以前测过同一穿戴设备。

输出描述

输出为一个整数,表示至少需要几台穿戴设备供测试。

用例输入

5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
3 5
4

解题思路

这是一个典型的图着色问题,其中每个员工可以看作图中的一个节点,而两个员工以前测过同一设备的关系可以看作图中的一条边。目标是为每个节点分配一个颜色(即穿戴设备),使得相邻节点(即以前测过同一设备的员工)不能有相同的颜色,并且使用的颜色总数最少。

方法一:贪心算法(基于饱和度优先的着色)

  1. 图的表示:使用邻接表表示图,其中每个节点存储与其相连的节点集合。
  2. 初始化
    • colors:存储每个节点的颜色,初始值为 -1(表示未着色)。
    • sat:存储每个节点的饱和度,即其邻居已使用的颜色数量。
    • degree:存储每个节点的度,即与其相连的节点数量。
  3. 选择节点:每次选择未着色且具有最高饱和度的节点进行着色。如果存在多个节点具有相同的饱和度,则选择度数最大的节点。
  4. 分配颜色:为选定的节点分配最小的未被其邻居使用的颜色。
  5. 更新饱和度:更新该节点的邻居的饱和度。
  6. 重复:重复上述过程,直到所有节点都被着色。
  7. 结果:使用的颜色总数即为所需的穿戴设备数量。

方法二:深度优先搜索(DFS)的回溯算法

  1. 图的表示:使用邻接矩阵表示图,其中 mp[i][j] 表示节点 ( i ) 和节点 ( j ) 之间是否存在边。
  2. 初始化
    • color:存储每个节点的颜色,初始值为 -1(表示未着色)。
    • res:存储当前找到的最小颜色数量。
  3. DFS搜索
    • 从节点 1 开始,尝试为每个节点分配颜色。
    • 对于每个节点,检查其邻居已使用的颜色,选择一个未被使用的最小颜色。
    • 如果当前节点无法分配颜色,则尝试分配一个新的颜色。
    • 递归地为下一个节点分配颜色。
    • 如果所有节点都被成功着色,更新结果。
  4. 回溯:如果当前分配的颜色数量已经超过当前结果,则回溯,尝试其他颜色分配。
  5. 结果:最终结果即为所需的穿戴设备数量。

代码

基于饱和度优先的着色 100%

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<set>
#include<list>
#include<sstream>
#include<bitset>
#include<stack>
#include<climits>
#include<iomanip>
#include<cstdint>
using namespace std;

int n, m;

// 每次选择未着色且具有最高饱和度的顶点进行着色
// 如果存在多个顶点具有相同的最高饱和度,则选择度数最大的顶点。
int choose(vector<int>& colors, vector<int>& sat, vector<int>& degree) {
    int max_s = -1;
    int max_d = -1;
    int v = -1;
    for (int i = 0; i < n; i++) {
        if (colors[i] == -1) {
            if (sat[i] > max_s || (sat[i] == max_s && degree[i] > max_d)) {
                max_s = sat[i];
                max_d = degree[i];
                v = i;
            }
        }
    }
    return v;
}

// 未被其邻居使用的最小颜色编号。
int get_color(int v, vector<set<int>>& used) {
    int cur = 0;
    while (used[v].count(cur)) {
        cur++;
    }
    return cur;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    vector<set<int>> g(n);
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        x--, y--;
        g[x].insert(y);
        g[y].insert(x);
    }
    vector<int> colors(n, -1);
    vector<int> sat(n, 0); // 饱和度
    vector<int> degree(n, 0); // 度
    for (int i = 0; i < n; i++) {
        degree[i] = g[i].size();
    }
    vector<set<int>> used(n);
    int maxc = -1;
    for (int i = 0; i < n; i++) {
        int v = choose(colors, sat, degree);
        if (v == -1) {
            break;
        }
        int cur = get_color(v, used);
        colors[v] = cur;
        maxc = max(maxc, cur);
        for (auto& nx : g[v]) {
            if (colors[nx] == -1) {
                if (!used[nx].count(cur)) {
                    used[nx].insert(cur);
                    sat[nx]++;
                }
            }
        }
    }
    cout << maxc + 1;
}

回溯 50%

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<set>
#include<list>
#include<sstream>
#include<bitset>
#include<stack>
#include<climits>
#include<iomanip>
#include<cstdint>
using namespace std;

int n, m;
int mp[105][105];
int res = INT_MAX;
int color[105];

// 当前节点 颜色数量
void dfs(int cur, int all) {
    if (cur == n + 1) {
        res = min(res, all);
        return;
    }
    if (res <= all) return;
    int no[105] = { 0 }; // 不能使用的颜色
    for (int i = 1; i < cur; i++) {
        if (mp[i][cur]) no[color[i]] = 1;
    }
    for (int i = 0; i <= all; i++) {
        if (!no[i]) {
            color[cur] = i;
            dfs(cur + 1, all);
        }
    }
    color[cur] = all + 1;
    dfs(cur + 1, all + 1);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            mp[i][j] = 0;
        }
    }
    cin >> m;
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        mp[x][y] = mp[y][x] = 1;
    }
    dfs(1, 0);
    cout << res + 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值