华为OD机试 2025B卷 - 无向图染色

真题目录: 点击去查看

2025B卷 200分题型

题目描述

给一个无向图染色,可以填红黑两种颜色,必须保证相邻两个节点不能同时为红色,输出有多少种不同的染色方案?

输入描述

第一行输入M(图中节点数) N(边数)

后续N行格式为:V1 V2表示一个V1到V2的边。

数据范围:1 <= M <= 15,0 <= N <= M * 3,不能保证所有节点都是连通的。

输出描述

输出一个数字表示染色方案的个数。

用例1

输入

4 4
1 2
2 4
3 4
1 3

输出

7

说明

4个节点,4条边,1号节点和2号节点相连,

2号节点和4号节点相连,3号节点和4号节点相连,

1号节点和3号节点相连,

若想必须保证相邻两个节点不能同时为红色,总共7种方案。

用例2

输入

3 3
1 2
1 3
2 3

输出

4

用例3

输入

4 3
1 2
2 3
3 4

输出

8

用例4

输入

4 3
1 2
1 3
2 3

输出

8

题解

思路:暴力枚举,题目数据量比较少直接使用m <= 15直接顶点所有颜色状态分配状态然后判断是否合法。

  1. 通过顶点数量确定枚举范围 [0 ,2^m - 1]
  2. 枚举的值代表一种分配方案,举个例子假设当前m = 3 枚举值为3 对应二进制位 011,我们设定二进制为1代表分配为红色,0代表分配为白色。
  3. 对于每个枚举值,合法性判断就是判断当前方案是否将相邻边同时分配为红色。假设有一个边对应两个顶点分别为x y,枚举值为i,对应判断表达式为(i >> (x-1) & 1) == 1 && (i >> (y-1) & 1) == 1. 如果当前所有边的合法性判断都通过则结果 + 1.
  4. 输出枚举完所有方案的结果。

c++

#include
#include
#include
#include  
#include 
#include 
#include
using namespace std;

int main() {
    int n,m;
    // 节点 边
    cin >> m >> n;
    vector> edges(n);
    for (int i = 0; i < n; i++) {
        int x , y;
        cin >> x >> y;
        edges[i] = {x, y};
    }
    // 没有边所以说明每个节点都能取红或黑
    if (n == 0) {
        cout << pow(2, m);
        return 0;
    }
    
    int res = 0;
    // 保留枚举所有情况判断是否合法 二进制方式枚举 二进制对应位 1 代表取红 0 代表为 黑
    for (int i = 0; i < (int)pow(2,m); i++) {
        // 判断是否合法
        bool flag = true;
        for (int j = 0; j < n; j++) {
            int x = edges[j].first;
            int y = edges[j].second;
            // 是否相邻边同为红 
            if ((i >> (x-1) & 1) == 1 && (i >> (y-1) & 1) == 1) {
                flag = false;
                break;   
            }
        }
        if (flag) {
            res++;
        }
    }
    
    cout << res;
    return 0;
}

JAVA

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 节点数 m,边数 n
        int m = sc.nextInt();
        int n = sc.nextInt();
        int[][] edges = new int[n][2];
        for (int i = 0; i < n; i++) {
            edges[i][0] = sc.nextInt();
            edges[i][1] = sc.nextInt();
        }

        // 没有边,说明每个节点可以独立染色为红或黑
        if (n == 0) {
            System.out.println((int)Math.pow(2, m));
            return;
        }

        int res = 0;
        // 枚举所有染色情况,用二进制方式表示染色状态
        for (int i = 0; i < (1 << m); i++) {
            boolean flag = true;
            for (int[] edge : edges) {
                int x = edge[0], y = edge[1];
                // 相邻节点不能同时为红色(即都为1)
                if (((i >> (x - 1)) & 1) == 1 && ((i >> (y - 1)) & 1) == 1) {
                    flag = false;
                    break;
                }
            }
            if (flag) res++;
        }
        System.out.println(res);
    }
}

Python

# 节点数 m,边数 n
m, n = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(n)]

# 没有边,每个节点可红或黑,共2^m种方案
if n == 0:
    print(2 ** m)
    exit()

res = 0
# 枚举所有染色情况,1表示红色,0表示黑色
for i in range(1 << m):
    valid = True
    for x, y in edges:
        if (i >> (x - 1)) & 1 and (i >> (y - 1)) & 1:
            valid = False
            break
    if valid:
        res += 1

print(res)

JavaScript

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let inputLines = [];

rl.on('line', (line) => {
    inputLines.push(line);
}).on('close', () => {
    const [m, n] = inputLines[0].split(' ').map(Number); // 读取节点数和边数
    const edges = inputLines.slice(1).map(line => line.split(' ').map(Number));

    if (n === 0) {
        console.log(2 ** m);  // 没有边,2^m 种方案
        return;
    }

    let res = 0;
    // 用二进制枚举所有染色方案
    for (let i = 0; i < (1 << m); i++) {
        let valid = true;
        for (const [x, y] of edges) {
            // 判断相邻节点是否都为红色(用1表示红色)
            if (((i >> (x - 1)) & 1) && ((i >> (y - 1)) & 1)) {
                valid = false;
                break;
            }
        }
        if (valid) res++;
    }

    console.log(res);
});

Go

package main

import (
	"fmt"
)

func main() {
	var m, n int
	fmt.Scan(&m, &n)

	edges := make([][2]int, n)
	for i := 0; i < n; i++ {
		fmt.Scan(&edges[i][0], &edges[i][1])
	}

	// 没有边,每个节点可以红或黑,总共 2^m 种方案
	if n == 0 {
		fmt.Println(1 << m)
		return
	}

	res := 0
	// 枚举所有染色方案,1 表示红色
	for i := 0; i < (1 << m); i++ {
		valid := true
		for _, edge := range edges {
			x, y := edge[0], edge[1]
			if ((i>>(x-1))&1) == 1 && ((i>>(y-1))&1) == 1 {
				valid = false
				break
			}
		}
		if valid {
			res++
		}
	}

	fmt.Println(res)
}

你可能感兴趣的:(华为od,华为OD2025B卷,华为OD机试2025B卷,华为OD机考2025B卷)