AtCoder真题及详细题解 ABC427C: Bipartize

AtCoder真题及详细题解 ABC427C: Bipartize

题目描述

有一个简单的无向图,包含 N N N 个顶点和 M M M 条边。该图由顶点 1 1 1、顶点 2 2 2、......、顶点 N N N 组成,第 i i i 条边( 1 ≤ i ≤ M 1 \le i \le M 1≤i≤M)连接顶点 u i u _ i ui 和 v i v _ i vi。

你将执行零次或多次以下操作:

  • 选择一条尚未被删除的边,并将其删除。

你的目标是使图变为二分图。找出使操作后的图变为二分图所需的最少操作次数。

简单图是什么意思?

简单图当且仅当没有自环(满足 u i = v i u _ i = v _ i ui=vi 的边)或重边(满足 u i = u j u _ i = u _ j ui=uj 且 v i = v j v _ i = v _ j vi=vj 的边对)时成立。

什么是二分图?

二分图是一种图,其中可以为每个顶点涂上黑色或白色,满足以下条件:

  • 对于每条边,该边连接的两个顶点颜色不同。
输入格式

输入从标准输入按以下格式给出:

N N N M M M
u 1 u _ 1 u1 v 1 v _ 1 v1
u 2 u _ 2 u2 v 2 v _ 2 v2
⋮ \vdots ⋮
u M u _ M uM v M v _ M vM

输出格式

输出使图变为二分图所需执行的操作次数。

输入输出样例 #1
输入 #1
复制代码
5 8
1 2
1 3
1 4
2 3
2 5
3 4
3 5
4 5
输出 1
复制代码
2
输入输出样例 2
输入 2
复制代码
2 1
1 2
输出 2
复制代码
0
输入输出样例 3
输入 3
复制代码
10 20
5 9
1 4
3 8
1 6
4 10
5 7
5 6
3 7
3 6
5 10
1 3
3 4
6 7
1 2
4 7
1 5
1 9
9 10
4 5
8 9
输出 3
复制代码
5
说明/提示
样例解释 1

你可以通过删除两条边使图变为二分图:例如,删除连接顶点 1 1 1 和 3 3 3 的边,以及连接顶点 3 3 3 和 5 5 5 的边。

通过一次或更少的操作无法使图变为二分图,因此输出 2

样例解释 2

图从一开始就是二分图。因此,需要执行的操作次数为 0 0 0。

约束条件
  • 2 ≤ N ≤ 10 2 \le N \le 10 2≤N≤10
  • 1 ≤ M ≤ N ( N − 1 ) 2 1 \le M \le \dfrac{N(N-1)}2 1≤M≤2N(N−1)
  • 1 ≤ u i < v i ≤ N ( 1 ≤ i ≤ M ) 1 \le u _ i < v _ i \le N \ (1 \le i \le M) 1≤ui<vi≤N (1≤i≤M)
  • 给定的图是简单图。
  • 所有输入值都是整数。

AC代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int n, m, t, color[11], ans = 100;  // color数组记录每个顶点的颜色(0或1),ans记录最小操作次数
struct node {
    int u, v;  // 存储边的结构体
} a[110];  // 存储所有边的数组

// 深度优先搜索函数,i表示当前正在处理的顶点编号
void dfs(int i) {
    // 如果所有顶点都已处理完毕
    if (i == n + 1) {
        int cnt = 0;  // 统计需要删除的边数
        
        // 遍历所有边
        for (int j = 1; j <= m; j++) {
            // 如果边的两个端点颜色相同,说明这条边需要删除
            if (color[a[j].u] == color[a[j].v]) {
                cnt++;
            }
        }
        
        // 更新最小操作次数
        ans = min(ans, cnt);
        return;
    }
    
    // 尝试将当前顶点染成颜色0,然后处理下一个顶点
    color[i] = 0;
    dfs(i + 1);
    
    // 尝试将当前顶点染成颜色1,然后处理下一个顶点
    color[i] = 1;
    dfs(i + 1);
}

int main() {
    cin >> n >> m;
    
    // 读入所有边
    for (int i = 1; i <= m; i++) {
        cin >> a[i].u >> a[i].v;
    }
    
    // 从顶点1开始深度优先搜索
    dfs(1);
    
    // 输出最小操作次数
    cout << ans;
    return 0;
}

算法思路

这是一个使用暴力搜索解决二分图判定问题的方案。由于题目中N的最大值为10,可以枚举所有可能的顶点着色方案。

核心思想

  • 二分图的定义:可以用两种颜色给所有顶点着色,使得任意一条边的两个端点颜色不同
  • 对于每个顶点,都有两种可能的颜色选择(0或1)
  • 通过DFS枚举所有可能的着色方案
  • 对于每种着色方案,统计违反二分图条件的边数(即两端点颜色相同的边数)
  • 取所有方案中的最小违规边数作为答案

关键步骤

  1. DFS枚举:递归地为每个顶点尝试两种颜色
  2. 边界条件:当处理完所有顶点后,评估当前着色方案
  3. 边检查:对于每条边,检查两个端点颜色是否相同
  4. 结果更新:记录所有方案中的最小违规边数

复杂度分析

  • 时间复杂度:O( 2 N 2^N 2N × M),其中N是顶点数,M是边数
  • 空间复杂度:O(N + M),用于存储颜色数组和边列表

文末福利:《12大高频考点专题集训》

https://edu.csdn.net/course/detail/40437 点击跳转到秘籍

cpp 复制代码
#include<bits/stdc++.h>
using namespace std; 
int main(){
    cout<<"############# 祝看到这篇秘籍的OIer: ###############";
    cout<<"#### AC不是偶然,一等奖是必然!祝你AK全场! ########";
    cout<<"############# 复赛夺魁,一等在手! #################";
    return 0;
}
相关推荐
gAlAxy...3 小时前
面试JAVASE基础(五)——Java 集合体系
java·python·面试·1024程序员节
ceclar1233 小时前
C++容器forward_list
开发语言·c++·list
ceclar1233 小时前
C++容器list
java·c++·list
B站计算机毕业设计之家3 小时前
计算机视觉python口罩实时检测识别系统 YOLOv8模型 PyTorch 和PySide6界面 opencv (建议收藏)✅
python·深度学习·opencv·计算机视觉·cnn·1024程序员节
大肘子咒你3 小时前
数字狂潮来袭
数据结构·c++·1024程序员节
hansang_IR3 小时前
【算法速成课 3】康托展开(Cantor Expansion)/ 题解 P3014 [USACO11FEB] Cow Line S
c++·算法·状态压缩·康托展开·排列映射
m0_748233643 小时前
【类与对象(中)】C++类默认成员函数全解析
开发语言·c++·算法
Lethehong3 小时前
首个多院区异构多活容灾架构,浙人医创新开新篇
1024程序员节·kingbasees
呆呆的猫4 小时前
【多模态】46、DeepSeek-OCR | 一张图片是否真能抵千词
ocr·1024程序员节