判断一个无向图是不是二分图

判断一个无向图是不是二分图,使用染色法.对每个顶点的相邻顶点染与顶点不同的颜色。如果染过色且与顶点颜色相同,则不是二分图。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 202;
vector<int>mp[maxn];
int color[maxn];

bool bfs(int s)
{
    color[s] = 0; //连通分支的起点可以染1也可以染0
    queue<int>q;
    q.push(s);
    while (!q.empty())
    {
        s = q.front();
        q.pop();
        for (int i = 0; i < (int)mp[s].size(); i ++) {
          int t = mp[s][i];
          if (color[t] == -1) color[t] = !color[s], q.push(t); //如果相邻顶点未被染色,则加入
                                                   //队列。
          if (color[t] == color[s]) { //如果相邻顶点染相同颜色,则不是二分图。
            return false;
          }
        }
    }
    return true;
}
int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF)
    {
        for (int i = 1; i <= n; i ++) mp[i].clear();
        memset(color, -1, (n+1)*sizeof(color[0]));
        for (int i = 0; i < m; i ++) {
            int x, y;
            cin >> x>>y;
            mp[x].push_back(y); //无向图存储两条边
            mp[y].push_back(x);
        }
        int flag = true; //初始化无向图是二分图
        for (int i = 1; i <= n; i ++) {
            if (color[i] == -1 && !bfs(i)) { //对每个连通分支染色,如果两个相邻的点
                    //颜色相同,则不是二分图。
                flag = false;
                break;
            }
        }
        if (!flag) cout <<"no"<<endl;
        else
            cout <<"yes"<<endl;
    }
    return 0;
}

The Accomodation of Students

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2757    Accepted Submission(s): 1287

Problem Description

There are a group of students. Some of them may know each other, while others don‘t. For example, A and B know each other, B and C know each other. But this may not imply that A and C know each other.

Now you are given all pairs of students who know each other. Your task is to divide the students into two groups so that any two students in the same group don‘t know each other.If this goal can be achieved, then arrange them into double rooms. Remember, only
paris appearing in the previous given set can live in the same room, which means only known students can live in the same room.

Calculate the maximum number of pairs that can be arranged into these double rooms.

Input

For each data set:

The first line gives two integers, n and m(1<n<=200), indicating there are n students and m pairs of students who know each other. The next m lines give such pairs.

Proceed to the end of file.

Output

If these students cannot be divided into two groups, print "No". Otherwise, print the maximum number of pairs that can be arranged in those rooms.

Sample Input

4 4
1 2
1 3
1 4
2 3
6 5
1 2
1 3
1 4
2 5
3 6

Sample Output

No
3
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 202;
vector<int>mp[maxn];
int color[maxn];
int matchx[maxn];
int matchy[maxn];
bool vis[maxn];
bool bfs(int s)
{
    color[s] = 0; //连通分支的起点可以染1也可以染0
    queue<int>q;
    q.push(s);
    while (!q.empty())
    {
        s = q.front();
        q.pop();
        for (int i = 0; i < (int)mp[s].size(); i ++) {
          int t = mp[s][i];
          if (color[t] == -1) color[t] = !color[s], q.push(t); //如果相邻顶点未被染色,则加入
                                                   //队列。
          if (color[t] == color[s]) { //如果相邻顶点染相同颜色,则不是二分图。
            return false;
          }
        }
    }
    return true;
}

bool dfs(const int& x, const int& n)
{
    for (int i = 0; i < (int)mp[x].size(); i ++) {
        int j = mp[x][i];
        if (vis[j] == false) {
            vis[j] = true;
            if (matchy[j] == -1 || dfs(matchy[j], n)) {
                matchy[j] = x;
                matchx[x] = j;
                return true;
            }
        }
    }
    return false;
}

int work(const int& n)
{
    int res = 0;
    memset(matchx, -1, (n+1)*sizeof(matchx[0]));
    memset(matchy, -1, (n+1)*sizeof(matchy[0]));
    for (int i = 1; i <= n; i ++) {
        memset(vis, 0, (n+1)*sizeof(vis[0]));
        if (matchx[i] == -1 && dfs(i, n)) res ++;
    }
    return res;
}

int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF)
    {
        for (int i = 1; i <= n; i ++) mp[i].clear();
        memset(color, -1, (n+1)*sizeof(color[0]));
        for (int i = 0; i < m; i ++) {
            int x, y;
            cin >> x>>y;
            mp[x].push_back(y); //无向图存储两条边
            mp[y].push_back(x);
        }
        int flag = true; //初始化无向图是二分图
        for (int i = 1; i <= n; i ++) {
            if (color[i] == -1 && !bfs(i)) { //对每个连通分支染色,如果两个相邻的点
                    //颜色相同,则不是二分图。
                flag = false;
                break;
            }
        }
        if (!flag) {puts("No"); continue;}
        int res = work(n);
        printf("%d\n", res/2);
    }
    return 0;
}
时间: 2024-11-05 00:01:28

判断一个无向图是不是二分图的相关文章

用并查集判断一个无向图中是否存在环

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示.集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并. Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集合. Union:将两个子集合并成同一个集合. 其实判断一个图是否存在环已经有相应的算法,此文用并查集来判断一个图是否有环. 我们可以用一个一维数组parent[] 来记录子集合. 看下面这个图: 0 |   \

利用并查集判断一个无向图是否成树

hdu 1272 利用并查集方法,找到各点的根节点. 几点注意: 一.树:1.无环 2.根节点入度为0,其余入度为1 判断依据: 1.若两个点的根节点相同(这两个点是父子关系),则形成环. 2.若所有点中只有一个点的根节点是他本身,则根节点入度为0. 二. 1. 0 0 :空树也是一颗树. 1 #include<iostream> 2 #include<algorithm> 3 #define Max 100005 4 using namespace std; 5 6 int f[

(转)判断一个图是否有环 无向图 有向图

无向图: 法1: 如果存在回路,则必存在一个子图,是一个环路.环路中所有顶点的度>=2. n算法: 第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一. 第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一. 如果最后还有未删除顶点,则存在环,否则没有环. n算法分析: 由于有m条边,n个顶点.如果m>=n,则根据图论知识可直接判断存在环路. (证明:如果没有环路,则该图必然是k棵树 k>=1.根据树的性质,边的数目m = n-k.k

判断一个图是否有环 无向图 有向图(转)

没有找到原文出处,请参考一下链接: http://www.cnblogs.com/hiside/archive/2010/12/01/1893878.html http://topic.csdn.net/u/20071023/11/3edb81fc-37b2-4506-906e-44dc0fc521f2.html 一.无向图: 方法1: 如果存在回路,则必存在一个子图,是一个环路.环路中所有顶点的度>=2. n算法: 第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度

【C++】判断一个图是否有环 无向图 有向图(转载)

没有找到原文出处,请参考一下链接: http://www.cnblogs.com/hiside/archive/2010/12/01/1893878.html http://topic.csdn.net/u/20071023/11/3edb81fc-37b2-4506-906e-44dc0fc521f2.html 一.无向图: 方法1: 如果存在回路,则必存在一个子图,是一个环路.环路中所有顶点的度>=2. n算法: 第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度

HDU 2444 The Accomodation of Students(判断是否可图 + 二分图)

题目大意:有一群人他们有一些关系,比如A认识B, B认识C, 但是这并不意味值A和C认识.现在给你所有互相认识的学生,你的任务是把所有的学生分成两个一组, 住在一个双人房里.相互认识的同学可以住在一个双人房里. 输入数据: 有n个学生 m个关系(m对是相互认识的) 接下来m行是,是m个关系. 如果能够匹配成功则输出需要双人房的个数,否则输出'No' 思路:先判断是否是个二分图,可以使用黑白染色的方法来判断.然后再进行最大匹配. #include<stdio.h> #include<str

oracle中如何判断一个字符串是否含有汉字

oracle中如何判断一个字符串是否含有汉字 一.1 BLOG文档结构图 一.2 前言部分 一.2.1 导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~: ①全角字符的判断,或者是含有汉字的字符串的判断 本文如有错误或不完善的地方请大家多多指正,ITPUB留言或QQ皆可,您的批评指正是我写作的最大动力. 一.2.2 实验环境介绍 11.2.0.3  RHEL6.5 一.2.3 本文简介 看到网友问,怎么查询表中某个字段数据是不是包含了

(hdu step 4.2.7)逃离迷宫(在有转弯次数的限制的情况下,判断一个点是否能到另一个点)

题目: 逃离迷宫 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 264 Accepted Submission(s): 85   Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍

分支结构判断一个月几天

int month = 0; scanf("%d",&month); switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: printf("%d月 31 天",month); break; case 4: case 6: case 9: case 11: printf("%d 月30天",month); break; case 2: print