HDU - 2444 The Accomodation of Students (二分图判定,二分图最大匹配)

题意:给出编号范围为N的人,然后再给出编号a b 之间有认识的关系。给出m组这样的关系,然后让你分出两组
使得每组中每个人互相都不认识(认识关系没有间接性),如果能分组的话,就将两个认识人放到一个房间中,求最多需要的房间数
思路:以前做过并查集关于分组的题所以首先想用并查集来试一下(并查集分组是开两倍的数组)
但是自析想想并查集分的时候实际上是有间接关系的,同时也不能判断怎样分配房间
然后就学习了:二分图匹配
二分图匹配问题就是给出一个图,只要两个点之间有边,那么这两个点就不能同属一个集合,必须分在两边。
(1)二分图的判定:这道题就判定是否是一个二分图:
方法:染色法 :我们可以从某个点出发,然后对其连接的点染色,该点染为1,连接的点染为2.如果
与其相连接的点已经染为1了,则说明这个肯定不是一个二分图
(2):二分图最大匹配:在所给定的图中我们尽可能使两两认识的在一起即我们可以每次
固定两个人的关系,并拿出图。将剩下的继续匹配,找到“增广路径”
(增广路径:有A、B集合,增广路由A中一个点通向B中一个点,再由B中这个点通向A中一个点……交替进行)

完整代码:

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 10010;
int n,m;//顶点数 边数 
vector<int> G[maxn];
int vis[maxn],match[maxn];
int color[maxn] ;
//0 没染色      1 -1不同色 
bool dfs(int u, int c){
    color[u] = c;
    for(int i=0; i<G[u].size(); i++){
        int v = G[u][i];
        //颜色相同不行
        if(color[v] == c)    return false;
        //v没有染色,递归染色判断这种情况是否成立
        if(color[v] == 0 && !dfs(v,-c))    return false;
    }
    return true;
}

bool solve(){
    for(int i=1; i<=n; i++){
        if(color[i] == 0)
            if(!dfs(i,1)){
                return false;
            } 
    }
    return true;
}
//匈牙利算法:dfs找到增广路径
bool Find(int u)
{
    for(int i=0; i<G[u].size(); i++)
    {
        int x = i;
        if(!vis[x] && G[u][x])
        {
            vis[x] = 1;
            if(!match[x] || Find(match[x]))
            {
                match[x] = u;
                return true;
            }
        }
    }
    return false;
}

int main(){
    int t;
    cin>>t;
    while(t--){
        cin >> n >> m;
        memset(color, 0, sizeof(color));
        for(int i=0; i<maxn; i++)    G[i].clear();
        for(int i = 0; i < m;  i++)
        {
            int s, t;
            cin >> s >> t;
            G[s].push_back(t);
            G[t].push_back(s);  // 如果有向图则无需这一句
        }
        
        if(solve()){
            memset(match,0,sizeof(match));
            for(int i=1;i<=n;i++){
                memset(vis,0,sizeof(vis));
                if(Find(i)) ans++;
            }
            cout<<ans/2<<endl;
        }
        else    cout<<"No"<<endl;
    }
    
    return 0;

}

bfs染色:

bool bfs(int s){
     color[s] = 1;
     queue<int>q;
     q.push(s);
     while(!q.empty()){
         int u = q.front();
         q.pop();
         for(int v = 1; v <= n; v++){
             //相邻且没有染色
             if(G[u][v] && color[v] == 0){
                 q.push(v);
                 color[v] = -color[u];//染上不同的颜色
             }
             if(G[u][v] && color[u] == color[v]){
                 return false;
             }
         }
     }
     //所有结点被染色且相邻结点颜色不一样
     return true;
 }

猜你喜欢

转载自www.cnblogs.com/Tianwell/p/11329268.html