zoukankan      html  css  js  c++  java
  • 二分图

    https://vjudge.net/contest/286149#problem/G 专题连接

    1.判二分图

    The Accomodation of Students

    //bfs法
    //先把一个点染色,然后把他周围联通的所有节点染色,如果染得颜色冲突,则不能形成二分图,如果没有染色,则染一个相反的颜色。 #include
    <cstdio> #include<algorithm> #include<cstring> #include<vector> #include<queue> using namespace std; const int maxm = 205; int line[maxm][maxm], used[maxm], nxt[maxm]; int col[maxm]; int n, m, u, v; bool fid(int x) { for(int i = 1; i <= n; i++) { if(line[x][i] && !used[i]) { used[i] = 1; if(nxt[i] == 0 || fid(nxt[i])) { nxt[i] = x; return true; } } } return false; } int match() { int sum = 0; for(int i = 1; i <= n; i++) { memset(used, 0, sizeof(used)); if(fid(i)) sum++; } return sum; } bool bfs() { for(int i = 1; i <= n; i++) { if(col[i] == -1) { col[i] = 0; queue<int> q; q.push(i); while(!q.empty()) { int k = q.front(); q.pop(); for(int j = 1; j <= n; j++) { if(line[k][j] && col[j] == col[k]) { return 0; } if(line[k][j] && col[j] == -1) { col[j] = 1 - col[k]; q.push(j); } } } } } return 1; } int main() { while(~scanf("%d%d", &n, &m)) { memset(col, -1, sizeof(col)); memset(line, 0, sizeof(line)); memset(nxt, 0, sizeof(nxt)); while(m--) { scanf("%d%d", &u, &v); line[u][v] = line[v][u] = 1; } if(!bfs()) { printf("No "); continue; } printf("%d ", match() / 2); } return 0; }
    #include<vector>
     
    using namespace std;
     
     
    static const int MAX = 10000;
    vector<int> G[MAX]; //
    int V;  //顶点数量
    int color[MAX]; //每个点的颜色(1,-1)
     
    //将顶点v染成颜色c,成功染色返回true,否则返回false
    bool dfs(int v, int c)
    {
        color[v] = c;
        for (int i = 0; i < G[v].size(); i++)
        {
            if (color[G[v][i]] == c)
                return false;   //相邻的点的颜色相同
            if (color[G[v][i]] == 0 && !dfs(G[v][i], -c))
                return false;
        }
        //所有点都染好颜色了
        return true;
    }
     
    void solve()
    {
        for (int i = 0; i < V; i++)
            if (color[i] == 0)
                if (!dfs(i, 1)) //未染色
                {
                    printf("No
    ");
                    return;
                }    
        printf("Yes
    ");
    }

    https://blog.csdn.net/flynn_curry/article/details/52966283

    这个讲了最大匹配,最小点覆盖,最小边覆盖,最大独立自己等等。

    Courses

     二分图邻接举证模板,复杂度势N* M;

    题意:n个课,m个人,保证取出所有课,所有课对应一个人。

    输入能上这个课的人的编号;例如 3 1 2 3 如果是在第一行,表示能上第一堂课的人有3个,分别是1,2,3.

    显示建二分图,左边表示课程,右边表示学生,如果学生能上某个可就连一条边,然后求最大匹配。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    
    using namespace std;
    const int maxm = 305;
    int line[maxm][maxm], used[maxm], nxt[maxm];
    int t, p, n, m, u, v;
    
    bool fid(int x) {
    for(int i = 1; i <= n; i++) {
        if(line[x][i] && !used[i]) {
            used[i] = 1;
            if(nxt[i] == 0 || fid(nxt[i])) {
                nxt[i] = x;
                return true;
            }
        }
    }
    return false;
    }
    int match() {
    int sum = 0;
    for(int i = 1; i <= p; i++) {
        memset(used, 0, sizeof(used));
        if(fid(i)) sum++;
    }
    return sum;
    }
    int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &p, &n);
        memset(line, 0, sizeof(line));
        memset(nxt, 0, sizeof(nxt));
        for(int i = 1; i <= p; i++) {
            scanf("%d", &m);
            while(m--) {
                scanf("%d", &v);
                line[i][v] = 1;
            }
    
        }
        if(p > n) {
            printf("NO
    ");
            continue;
        }
    
    if(match() == p) {
        printf("YES
    ");
    }
    else {
        printf("NO
    ");
    }
    }
    
    return 0;
    }
    //邻接表版本。
    #include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int maxm = 605; vector<int> ve[maxm]; int match[maxm]; bool used[maxm]; int t, p, n, m; void add(int u, int v) { ve[u].push_back(v); ve[v].push_back(u); } bool dfs(int v) { used[v] = 1; for(int i = 0; i < ve[v].size(); i++) { int u = ve[v][i]; int w = match[u]; if(w < 0 || (!used[w] && dfs(w) )) { match[v] = u;; match[u] = v; return true; } } return false; } int ma() { int res = 0; memset(match, -1, sizeof(match)); for(int i = 1; i <= p; i++) { if(match[i] < 0) { memset(used, 0, sizeof(used)); if(dfs(i)) { res++; } } } return res; } int main() { scanf("%d", &t); while(t--) { scanf("%d%d", &p, &n); for(int i = 1; i <= p + n; i++) { ve[i].clear(); } int v; for(int i = 1; i <= p; i++) { scanf("%d", &m); while(m--) { scanf("%d", &v); add(i, v + p); } }
    //建图过程中把课程编号为1-p,把学生编号为p + 1, p + n;然后进行二分图匹配。
    if(p > n) { printf("NO "); continue; } if(ma() == p) { printf("YES "); } else { printf("NO "); } } return 0; }

    https://wenku.baidu.com/view/63c1a01655270722192ef7c3.html

    https://blog.csdn.net/juncoder/article/details/38346193

    建图方式的博客。主要是建图。

  • 相关阅读:
    Word操作——通配符
    圆的拟合
    最优化案例整理
    机器学习数学基础知识备忘
    scikit-learn学习笔记
    Linux下安装scikit-learn
    ROS学习备忘
    [ROS]激光驱动安装
    CMake和Linux编程:find_package的使用
    [OpenCV]直线拟合
  • 原文地址:https://www.cnblogs.com/downrainsun/p/10490591.html
Copyright © 2011-2022 走看看