• HDU


    题意:给出编号范围为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;
     }
  • 相关阅读:
    SQL server 导出平面文件时出错: The code page on Destination
    中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
    C# DataTable 转 List(大家进来讨论讨论)
    CSS3圆角气泡框,评论对话框
    WinForm 换行问题 textbox (转)
    Nhibernate 多对多级联删除
    JS、C# 去除html标签
    Nhibernate 多对多级联更新
    Ext.Ajax.request()方法和FormPanel.getForm().submit()方法,都返回success()方法的差异
    ExtJs 4.2.1 报错:Uncaught TypeError: Cannot call method 'getItems' of null
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11329268.html
Copyright © 2020-2023  润新知