#P2285. 第1题-绩效互评人员分配
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 668
            Accepted: 245
            Difficulty: 6
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2024年9月27日-国内
                              
                      
          
 
- 
                        算法标签>DFS          
 
第1题-绩效互评人员分配
前置知识:二分图以及它的判定
塔子哥找的一个比较高质量的讲解贴。大家想彻底搞清楚的可以去看看!
https://blog.csdn.net/m0_63997099/article/details/140763017
题面解释:
给定一个整数n表示员工人数,以及一个n行的邻接表数组,描述员工之间的同学或同团队关系。要求将这n个人分成两组,使得每组内没有同学或同团队的员工。输出按编号从小到大排序的最优分组方案,如果无法分组,则输出−1。
思路
单纯的二分图染色,处理完输入之后,开始进行染色,如果不是二分图进行标记停止染色。对染色后的图,存进两个数组里,比较一下谁小,在先输出谁即可。代码实现为dfs染色 对于一个无向图,起初图中所有顶点都是无色,我们从任意未染色顶点出发,对这个顶点进行染色,对于与这个顶点相邻的的顶点,有三种情况: 1、未染色 那么将这个顶点染色,染与当前顶点不相同的颜色。 2、已经染色但是当前顶点颜色不同 那么跳过该顶点 3、已经染色但是与当前顶点相同。则该图不是一个二分图,返回失败。 图中所有顶点已经进行染色,并且没有出现相邻顶点颜色相同的情况,则该图是一个二分图。
题解
- 
初始化:
- 使用一个邻接表
GoodRelationships存储员工之间的关系。 - 使用一个
color数组记录每个员工的颜色(或分组),0表示未染色,1和2表示不同的组。 
 - 使用一个邻接表
 - 
深度优先搜索(DFS)染色:
- 从任意一个未染色的节点开始,进行DFS染色。
 - 对于当前节点
u,我们将其染成颜色c。 - 遍历所有与
u相邻的节点v:- 如果
v已染色且颜色与u相同,则说明图不是二分图,标记为失败。 - 如果
v未染色,则将其染成与u不同的颜色(3 - c)。 
 - 如果
 
 - 
检查每个节点:
- 遍历所有节点,如果某个节点未染色,则从该节点开始DFS,确保所有分支都被检查。
 
 - 
分组结果:
- 根据
color数组的值,将节点分为两个组。 - 输出时比较两个组的第一个员工编号,以确定输出的顺序,确保输出最小的方案。
 
 - 根据
 - 
边界条件:
- 若在DFS过程中发现图不是二分图,直接输出−1。
 
 
代码如下
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
// 定义图的邻接表,最大105个员工
vector<int> GoodRelationships[105];
int color[105];  // 记录每个节点的颜色,0表示未染色,1和2表示不同的组
bool is_bipartite = true;  // 判断是否为二分图
// 深度优先搜索函数,u为当前节点,c为当前颜色(组)
void dfs(int u, int c) {
    if (!is_bipartite) return;
    color[u] = c;
    for (int v : GoodRelationships[u]) {
        if (color[v] == c) {  // 如果相邻节点颜色相同,说明无法分组
            is_bipartite = false;
            return;
        }
        if (color[v] == 0) {  // 如果相邻节点未染色,则染上相反颜色
            dfs(v, 3 - c);
        }
    }
}
int main() {
    int n;  // n 表示员工数量
    cin >> n;
    cin.ignore();  // 忽略换行符
    // 输入邻接表数据
    for (int i = 0; i < n; i++) {
        string line;
        getline(cin, line);
        int num = 0;
        for (int j = 0; j < line.size(); j++) {
            if (line[j] == ' ') {
                GoodRelationships[i].push_back(num);
                num = 0;
            } else {
                num = num * 10 + (line[j] - '0');
            }
        }
        if (num != 0) {
            GoodRelationships[i].push_back(num);
        }
    }
    // 检查每个节点,如果未染色则从该节点开始dfs
    for (int i = 0; i < n; i++) {
        if (color[i] == 0) {
            dfs(i, 1);  // 初始从颜色1开始
        }
    }
    // 如果无法分组,输出 -1
    if (!is_bipartite) {
        cout << -1 << endl;
        return 0;
    }
    vector<int> group1, group2;  // 分成两组
    // 按颜色将节点分组
    for (int i = 0; i < n; i++) {
        if (color[i] == 1) {
            group1.push_back(i);
        } else {
            group2.push_back(i);
        }
    }
    // 输出分组结果,选择编号最小的方案
    if (group1[0] > group2[0]) {
        swap(group1, group2);
    }
    for (int v : group1) {
        cout << v << " ";
    }
    cout << endl;
    for (int v : group2) {
        cout << v << " ";
    }
    cout << endl;
    return 0;
}
python
def dfs(u, color, adj, color_group):
    global is_bipartite
    if not is_bipartite:
        return
    color_group[u] = color
    for v in adj[u]:
        if color_group[v] == color:
            is_bipartite = False
            return
        if color_group[v] == 0:
            dfs(v, 3 - color, adj, color_group)
def main():
    import sys
    global is_bipartite
    is_bipartite = True
    n = int(sys.stdin.readline())
    adj = [[] for _ in range(n)]
    
    for i in range(n):
        line = sys.stdin.readline().strip()
        if line:
            numbers = list(map(int, line.split()))
            adj[i].extend(numbers)
    color_group = [0] * n  # 记录每个节点的颜色
    for i in range(n):
        if color_group[i] == 0:
            dfs(i, 1, adj, color_group)
            if not is_bipartite:
                break
    if not is_bipartite:
        print(-1)
        return
    group1 = []
    group2 = []
    for i in range(n):
        if color_group[i] == 1:
            group1.append(i)
        else:
            group2.append(i)
    # 确保 group1 的第一个元素编号更小
    if group1 and group2 and group1[0] > group2[0]:
        group1, group2 = group2, group1
    print(' '.join(map(str, group1)))
    print(' '.join(map(str, group2)))
if __name__ == "__main__":
    main()
java
import java.util.*;
public class Main {
    // 定义图的邻接表
    static List<Integer>[] GoodRelationships;
    static int[] colorGroup;  // 记录每个节点的颜色,0表示未染色,1和2表示不同的组
    static boolean isBipartite = true;  // 判断图是否为二分图
    // 深度优先搜索函数,u为当前节点,c为当前颜色(组)
    public static void dfs(int u, int c) {
        if (!isBipartite) return;
        colorGroup[u] = c;
        for (int v : GoodRelationships[u]) {
            if (colorGroup[v] == c) {  // 如果相邻节点颜色相同,说明无法分组
                isBipartite = false;
                return;
            }
            if (colorGroup[v] == 0) {  // 如果相邻节点未染色,则染上相反颜色
                dfs(v, 3 - c);
            }
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  // n 表示员工数量
        sc.nextLine();  // 忽略换行符
        // 初始化邻接表
        GoodRelationships = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            GoodRelationships[i] = new ArrayList<>();
        }
        // 输入邻接表数据
        for (int i = 0; i < n; i++) {
            String line = sc.nextLine().trim();
            if (!line.isEmpty()) {
                String[] parts = line.split("\\s+");
                for (String part : parts) {
                    int num = Integer.parseInt(part);
                    GoodRelationships[i].add(num);
                }
            }
        }
        colorGroup = new int[n];  // 初始化颜色数组
        // 检查每个节点,如果未染色则从该节点开始 DFS
        for (int i = 0; i < n; i++) {
            if (colorGroup[i] == 0) {
                dfs(i, 1);  // 初始从颜色1开始
                if (!isBipartite) break;
            }
        }
        // 如果无法分组,输出 -1
        if (!isBipartite) {
            System.out.println(-1);
            return;
        }
        List<Integer> group1 = new ArrayList<>();
        List<Integer> group2 = new ArrayList<>();
        // 按颜色将节点分组
        for (int i = 0; i < n; i++) {
            if (colorGroup[i] == 1) {
                group1.add(i);
            } else {
                group2.add(i);
            }
        }
        // 确保 group1 的第一个元素编号更小
        if (!group1.isEmpty() && !group2.isEmpty() && group1.get(0) > group2.get(0)) {
            List<Integer> temp = group1;
            group1 = group2;
            group2 = temp;
        }
        // 输出分组结果
        for (int v : group1) {
            System.out.print(v + " ");
        }
        System.out.println();
        for (int v : group2) {
            System.out.print(v + " ");
        }
        System.out.println();
    }
}
        题目内容
公司组织绩效互评,为了避免有同学或者同团队的人互相打高分,需要将员工分成两组分别打分。给定一个整数n和一个数组GoodRelationShips[][],其中,n表示人数,数组GoodRelationShips[][]是一个邻接表,GoodRelationShips[i]的元素[a,b,c]代表员工i和员工a,b,c是同学或者同团队。
请将这n个人分成两组,使其每组不再有同学或者同团队的人。
GoodRelationShips[][]的长度范围为[1,100]。
GoodRelationShips[i]中的元素的范围为[1,GoodRelationShips.length−1]。
GoodRelationShips[i]不会包含i或者有重复的值。
图是无向的:如果j在GoodRelationShips[1]里边,那么i也会在 GoodRelationShips[j]里边。
说明
保证给出的图是联通图
输入描述
数组形式的员工关系邻接表,第一行数字代表有N个顶点,顶点编号从0开 始,后续接N行。第i行代表第i−1个顶点和他有关系的同学的顶点编号
输出描述
分组方案按照节点编号从小到大排序,如两个方案第一个节点相同,则按照第二个节点排序,以此类推;方案内部也按照编号从小到大排序。输出排序最靠前的一种方案,如无法分成符合条件的两组,则输出−1
如输出如下两种方案时,选择第一种方案,因为方案一的分组2第一个节点编号更小:
分组1:1
分组2:2 3 4 5
和
分组1:1 2
分组2:3 4 5
如输出如下两种方案时,选择第二种方案,因为方案二的分组2第一个节点编号更小:
分组1:1 2
分组2:3 4 5
和
分组1:1 3
分组2:2 4 5
样例1
输入
4
1 3
0 2
1 3
0 2
输出
0 2
1 3
说明
无向图如下:

样例2
输入
4
1 2 3
0 2
0 1 3
0 2
输出
-1
说明
无向图如下:
