zoukankan      html  css  js  c++  java
  • kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

    二分匹配:二分图的一些性质

    二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

    1。一个二分图中的最大匹配数等于这个图中的最小点覆盖数

    König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。

    2。最小路径覆盖=最小路径覆盖=|G|-最大匹配数  在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,  且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,  那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.

    由上面可以得出:

     1.一个单独的顶点是一条路径;  2.如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的    顶点之间存在有向边.

    最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖.

     路径覆盖与二分图匹配的关系:最小路径覆盖=|G|-最大匹配数;

    3。二分图最大独立集=顶点数-二分图最大匹配

    独立集:图中任意两个顶点都不相连的顶点集合。

    二分图判定:染色判定法

    直接利用题目HDU 2444 The Accomodation of Students

    题意:给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识;

    现想将学生两两分组,且保证每一组的学生都认识,这样分组可达到的最大组数为多大?

    二分图判定+二分图最大匹配 直接看代码

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 410;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN],N,M;
    int color[MAXN];
    
    bool bipartite(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (color[v] == color[u]) return false;
            if (!color[v])
            {
                color[v] = 3 - color[u];
                if (!bipartite(v)) return false;
            }
        }
        return true;
    }
    
    bool dfs(int u)
    {
        for (int i = head[u]; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        memset(linker,-1,sizeof(linker));
        int ret = 0;
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    int main()
    {
        while (scanf("%d%d",&N,&M) != EOF)
        {
            init();
            memset(color,0,sizeof(color));
            for (int i = 0 ; i < M ; i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                add_edge(u,v,9797);
               // add_edge(v,u,9797);
            }
            bool flag = false;
            for (int i = 1 ; i <= N ; i++)
            {
                if (color[i] == 0)
                {
                    color[i] = 1;
                    if (!bipartite(i))
                    {
                        flag = true;
                        break;
                    }
                }
            }
            if (!flag)
            {
                printf("%d
    ",calcu());
            }
            else puts("No");
        }
        return 0;
    }
    View Code

    ————————————————————————————————————————————————————————————————————————————————————————————

    2份模板

    1:匈牙利算法 点编号从1开始到N 复杂度O(VE)

    const int MAXN = 110;
    const int MAXM = 100010;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN],N,n;
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0 ;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    View Code

    第二份 Hopcroft_Krap 复杂度O(根号V*E) 这份模板从0点编号

    const int MAXN = 3010;
    const int MAXM = 3000010;
    const int INF = 0x3f3f3f3f;
    vector<int>G[MAXN];
    int uN;
    int MX[MAXN],MY[MAXN];
    int dx[MAXN],dy[MAXN];
    int dis;
    bool used[MAXN];
    
    bool searchp()
    {
        queue<int>q;
        dis = INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for (int i = 0 ; i < uN ; i++)
        {
            if (MX[i] == -1)
            {
                q.push(i);
                dx[i] = 0;
            }
        }
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            if (dx[u] > dis) break;
            int sz = G[u].size();
            for (int i = 0 ; i < sz ; i++)
            {
                int v = G[u][i];
                if (dy[v] == -1)
                {
                    dy[v] = dx[u] + 1;
                    if (MY[v] == -1) dis = dy[v];
                    else
                    {
                        dx[MY[v]] = dy[v] + 1;
                        q.push(MY[v]);
                    }
                }
            }
        }
        return dis != INF;
    }
    
    bool dfs(int u)
    {
        int sz = G[u].size();
        for (int i = 0 ; i < sz ; i++)
        {
            int v = G[u][i];
            if (!used[v] && dy[v] == dx[u] + 1)
            {
                used[v] = true;
                if (MY[v] != -1 && dy[v] == dis) continue;
                if (MY[v] == -1 || dfs(MY[v]))
                {
                    MY[v] = u;
                    MX[u] = v;
                    return true;
                }
            }
        }
        return false;
    }
    
    int Maxmatch()
    {
        int ret = 0;
        memset(MX,-1,sizeof(MX));
        memset(MY,-1,sizeof(MY));
        while (searchp())
        {
            memset(used,false,sizeof(used));
            for (int i = 0 ; i < uN; i++)
                if (MX[i] == -1 && dfs(i)) ret++;
        }
        return ret;
    }
    View Code

    用第一道题来表示这2个模板怎么用的

    HDU 1045 Fire Net

    题意:在有墙的图中放尽量多的车满足相互不可攻击,球最多放多少个车;

    建图:因为有墙的原因不可按照经典二分图简单建图,可以重新最每个点所在的行列进行编号。如果遇到墙或者到达边界编号更新。具体看代码

    2分代码来显示模板用法 1:匈牙利

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 110;
    const int MAXM = 100010;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN],N,n;
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0 ;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    char G[10][10];
    int idrow[10][10],idcol[10][10];
    int main()
    {
       // freopen("sample.txt","r",stdin);
        while (scanf("%d",&n) != EOF)
        {
            if (n == 0) break;
            for (int i = 1 ; i <= n ; i++) scanf("%s",G[i] + 1);
            init();
            int idx = 1,idy = 1;
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    if (G[i][j] == 'X') idx++;
                    else idrow[i][j] = idx;
                    if (j == n) idx++;
                   // printf("%d ",idrow[i][j]);
                }
            }
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    if (G[j][i] == 'X') idy++;
                    else idcol[j][i] = idy;
                    if(j == n) idy++;
                    //printf("%d ",idcol[i][j]);
                }
            }
           // printf("%d %d
    ",idx,idy);
            N = idx - 1;
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    if (G[i][j] == '.')
                        add_edge(idrow[i][j],idcol[i][j],9797);
                }
            }
            printf("%d
    ",calcu());
        }
        return 0;
    }
    View Code

    2:HK

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 3010;
    const int MAXM = 3000010;
    const int INF = 0x3f3f3f3f;
    vector<int>G[MAXN];
    int uN;
    int MX[MAXN],MY[MAXN];
    int dx[MAXN],dy[MAXN];
    int dis;
    bool used[MAXN];
    
    bool searchp()
    {
        queue<int>q;
        dis = INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for (int i = 0 ; i < uN ; i++)
        {
            if (MX[i] == -1)
            {
                q.push(i);
                dx[i] = 0;
            }
        }
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            if (dx[u] > dis) break;
            int sz = G[u].size();
            for (int i = 0 ; i < sz ; i++)
            {
                int v = G[u][i];
                if (dy[v] == -1)
                {
                    dy[v] = dx[u] + 1;
                    if (MY[v] == -1) dis = dy[v];
                    else
                    {
                        dx[MY[v]] = dy[v] + 1;
                        q.push(MY[v]);
                    }
                }
            }
        }
        return dis != INF;
    }
    
    bool dfs(int u)
    {
        int sz = G[u].size();
        for (int i = 0 ; i < sz ; i++)
        {
            int v = G[u][i];
            if (!used[v] && dy[v] == dx[u] + 1)
            {
                used[v] = true;
                if (MY[v] != -1 && dy[v] == dis) continue;
                if (MY[v] == -1 || dfs(MY[v]))
                {
                    MY[v] = u;
                    MX[u] = v;
                    return true;
                }
            }
        }
        return false;
    }
    
    int Maxmatch()
    {
        int ret = 0;
        memset(MX,-1,sizeof(MX));
        memset(MY,-1,sizeof(MY));
        while (searchp())
        {
            memset(used,false,sizeof(used));
            for (int i = 0 ; i < uN; i++)
                if (MX[i] == -1 && dfs(i)) ret++;
        }
        return ret;
    }
    
    char g[10][10];
    int n;
    int idrow[10][10],idcol[10][10];
    int main()
    {
        //freopen("sample.txt","r",stdin);
        while (scanf("%d",&n) != EOF)
        {
            if (n == 0) break;
            for (int i = 0 ; i <= n * n ; i++)G[i].clear();
            for (int i = 1 ; i <= n ; i++) scanf("%s",g[i] + 1);
            int idx = 0,idy = 0;
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    if (g[i][j] == 'X') idx++;
                    else idrow[i][j] = idx;
                    if (j == n) idx++;
                   // printf("%d ",idrow[i][j]);
                }
            }
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    if (g[j][i] == 'X') idy++;
                    else idcol[j][i] = idy;
                    if(j == n) idy++;
                    //printf("%d ",idcol[i][j]);
                }
            }
           // printf("%d %d
    ",idx,idy);
           // N = idx - 1;
            uN = idx;
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    if (g[i][j] == '.') G[idrow[i][j]].push_back(idcol[i][j]);
                       // add_edge(idrow[i][j],idcol[i][j],9797);
                }
            }
            printf("%d
    ",Maxmatch());
        }
        return 0;
    }
    View Code

    HDU 1083 Courses

    题意就是选个课代表。很简单直接做

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 310;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN],N,P;
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= P ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&P,&N);
            init();
            for (int i = 1 ; i <= P ; i++)
            {
                int cnt;
                scanf("%d",&cnt);
                while(cnt--)
                {
                    int x;
                    scanf("%d",&x);
                    add_edge(i,x,9797);
                }
            }
            printf("%s
    ",calcu() >= P ? "YES" : "NO");
        }
        return 0;
    }
    View Code

    HDU 1281 棋盘游戏

    中文题目

    一开始觉得这题好难。没想到直接爆就行了

    先求一边最大匹配,然后根据标记的linker数组吧对应匹配删掉,同时删掉这条边,然后重新跑匈牙利看是不是最大匹配变化即可

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 210;
    const int INF = 0x3f3f3f3f;
    const int MAXM = MAXN * MAXN;
    int N,M,K;
    int G[MAXN][MAXN];
    
    void init()
    {
        memset(G,0,sizeof(G));
    }
    
    bool used[MAXN];
    int linker[MAXN],rlinker[MAXN];
    int important;
    
    bool dfs(int u,bool first)
    {
        for (int i = 1 ; i <= N ; i++)
        {
            if (!G[u][i]) continue;
            int v = i;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v],first))
                {
                    if (first)
                    {
                        linker[v] = u;
                        rlinker[u] = v;
                    }
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        memset(rlinker,-1,sizeof(rlinker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i,true)) ret++;
        }
        return ret;
    }
    
    bool judge()
    {
        for (int i = 1;  i <= N ; i++)
        {
            if (rlinker[i] != -1) continue;
            memset(used,false,sizeof(used));
            if (dfs(i,false)) return false;
        }
        return true;
    }
    
    int main()
    {
        //freopen("sample.txt","r",stdin);
        int kase = 1;
        while (scanf("%d%d%d",&N,&M,&K) != EOF)
        {
            init();
            for (int i = 0 ; i < K ; i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                G[u][v] = true;
            }
            int num = calcu();
            important = 0;
            for (int u = 1 ; u <= N ; u++)
            {
                if (rlinker[u] == -1) continue;
                int v = rlinker[u];
                G[u][v] = false;
                linker[v] = -1;
                rlinker[u] = -1;
                if (judge()) important++;
                G[u][v] = true;
                linker[v] = u;
                rlinker[u] = v;
            }
            printf("Board %d have %d important blanks for %d chessmen.
    ",kase++,important,num);
        }
        return 0;
    }
    View Code

    HDU 2819 Swap
    交换某两行或者某两列使得主对角线全都是1

    首先交换行和列是等价的。

    建图:如果第i行的第j个数字为1,那么i和j连一条边,表示如果交换第i行第j行那么矩阵中A[j][j] = 1;

    建图之后跑最大匹配,如果最大匹配小于行数,那么不可行

    否则 就按照上面建图的方式输出答案,注意上面的建图是基于行列一开始的样子,输出是要一步一步的,每一步交换都会影响后边的。这里根据

    linker数组处理就好

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 210;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    int N;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v ,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    vector<pair<int,int> >ans;
    
    int main()
    {
        //freopen("sample.txt","r",stdin);
        while (scanf("%d",&N) != EOF)
        {
            init();
            ans.clear();
            for (int i = 1 ; i <= N ; i++)
            {
                for (int j = 1; j <= N; j++)
                {
                    int x;
                    scanf("%d",&x);
                    if(x) add_edge(i,j,9797);
                }
            }
            int ret = calcu();
            if (ret < N) puts("-1");
            else
            {
                for (int i = 1 ; i <= N ; i++)
                {
                    int j;
                    for (j = 1 ; j <= N;  j++)
                        if (linker[j] == i) break;
                    if (i != j)
                    {
                        ans.push_back(make_pair(i,j));
                        swap(linker[i],linker[j]);
                    }
                }
                printf("%d
    ",ans.size());
                for (int i = 0 ; i < (int)ans.size() ; i++)
                {
                    printf("C %d %d
    ",ans[i].first,ans[i].second);
                }
            }
        }
        return 0;
    }
    View Code

    HDU 2389 Rain on your Parade
    这里必须要用HK求。裸题

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 3010;
    const int MAXM = 3000010;
    const int INF = 0x3f3f3f3f;
    vector<int>G[MAXN];
    int uN;
    int MX[MAXN],MY[MAXN];
    int dx[MAXN],dy[MAXN];
    int dis;
    bool used[MAXN];
    
    bool searchp()
    {
        queue<int>q;
        dis = INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for (int i = 0 ; i < uN ; i++)
        {
            if (MX[i] == -1)
            {
                q.push(i);
                dx[i] = 0;
            }
        }
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            if (dx[u] > dis) break;
            int sz = G[u].size();
            for (int i = 0 ; i < sz ; i++)
            {
                int v = G[u][i];
                if (dy[v] == -1)
                {
                    dy[v] = dx[u] + 1;
                    if (MY[v] == -1) dis = dy[v];
                    else
                    {
                        dx[MY[v]] = dy[v] + 1;
                        q.push(MY[v]);
                    }
                }
            }
        }
        return dis != INF;
    }
    
    bool dfs(int u)
    {
        int sz = G[u].size();
        for (int i = 0 ; i < sz ; i++)
        {
            int v = G[u][i];
            if (!used[v] && dy[v] == dx[u] + 1)
            {
                used[v] = true;
                if (MY[v] != -1 && dy[v] == dis) continue;
                if (MY[v] == -1 || dfs(MY[v]))
                {
                    MY[v] = u;
                    MX[u] = v;
                    return true;
                }
            }
        }
        return false;
    }
    
    int Maxmatch()
    {
        int ret = 0;
        memset(MX,-1,sizeof(MX));
        memset(MY,-1,sizeof(MY));
        while (searchp())
        {
            memset(used,false,sizeof(used));
            for (int i = 0 ; i < uN; i++)
                if (MX[i] == -1 && dfs(i)) ret++;
        }
        return ret;
    }
    
    int Time,N,M;
    int X[MAXN],Y[MAXN],v[MAXN];
    int umbx[MAXN],umby[MAXN];
    
    int main()
    {
        int T,kase = 1;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&Time,&M);
            for (int i = 0 ; i < M ; i++)
                scanf("%d%d%d",&X[i],&Y[i],&v[i]);
            for (int i = 0 ; i < M ; i++)G[i].clear();
            uN = M;
            scanf("%d",&N);
            for (int i = 0 ; i < N ; i++)
                scanf("%d%d",&umbx[i],&umby[i]);
            for (int i = 0 ; i < M ; i++)
            {
                for (int j = 0 ; j < N ; j++)
                {
                    double dist = sqrt((umbx[j] - X[i]) * (umbx[j] - X[i])
                            + (umby[j] - Y[i]) * (umby[j] - Y[i]));
                   // printf("%d %d %lf
    ",i,j,dist);
                    if (1.0 * v[i] * Time >= dist)
                        G[i].push_back(j);
                }
            }
            printf("Scenario #%d:
    ",kase++);
            printf("%d
    
    ",Maxmatch());
        }
        return 0;
    }
    View Code

    HDU 4185 Oil Skimming
    最多有多少个相邻的2个#。

    每个#号编号,相邻则连边跑最大匹配,最后答案除以2

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 610;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    const int dx[] = {0,0,-1,1};
    const int dy[] = {1,-1,0,0};
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    int n;
    int N,M;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    char G[MAXN][MAXN];
    int id[MAXN][MAXN];
    int main()
    {
        int T,kase = 1;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d",&n);
            memset(id,0,sizeof(id));
            int idx = 1;
            for (int i = 1 ; i <= n ; i++)
                scanf("%s",G[i] + 1);
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    if (G[i][j] == '#') id[i][j] = idx++;
                }
            }
            N = idx - 1;
            init();
            for (int i = 1 ; i <= n ; i++)
            {
                for (int j = 1 ; j <= n ; j++)
                {
                    for (int d = 0 ; d < 4 ; d++)
                    {
                        int nx = i + dx[d];
                        int ny = j + dy[d];
                        if (nx >= 1 && nx <= n && ny >= 1 && ny <= n && G[nx][ny] == '#')
                        {
                            add_edge(id[i][j],id[nx][ny],9797);
                        }
                    }
                }
            }
            printf("Case %d: %d
    ",kase++,calcu() / 2);
        }
        return 0;
    }
    View Code

    POJ 3020 Antenna Placement

    跟上题类似。注意答案为什么是总数-匹配数/2

    首先一次匹配连接2个点。那么含义就是有2个点连在一起的边有这么多个。剩下的一个点占用2个的资源。说的不清楚看下面的式子

    实际上的式子为点总数 - (最大匹配)/2 * 2 + (最大匹配 / 2);

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 410;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    const int dx[] = {0,0,-1,1};
    const int dy[] = {1,-1,0,0};
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    int un,vn;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u]; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= un ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret++;
    }
    
    int N,M;
    int id[50][50];
    char G[50][50];
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&N,&M);
            for (int i = 1 ; i <= N ; i++) scanf("%s",G[i] + 1);
            int leap = 0;
            for (int i = 1 ; i <= N ; i++)
            {
                for (int j = 1;  j <= M ; j++)
                {
                    if (G[i][j] == '*') id[i][j] = ++leap;
                }
            }
            init();
            un = leap;
            for (int i = 1 ; i <= N ; i++)
            {
                for (int j = 1 ; j <= M ; j++)
                {
                    if (G[i][j] != '*') continue;
                    for (int d = 0 ; d < 4 ; d++)
                    {
                        int nx = i + dx[d];
                        int ny = j + dy[d];
                        if (nx >= 1 && nx <= N && ny >= 1 && ny <= M && G[nx][ny] == '*')
                        {
                            add_edge(id[i][j],id[nx][ny],9797);
                        }
                    }
                }
            }
            printf("%d
    ",leap - calcu() / 2);
        }
        return 0;
    }
    View Code

    HDU 1054 Strategic Game
    求最小点覆盖

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1510;
    const int MAXM = 200010;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    int un,vn;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 0;  i <= un ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    int N;
    
    int main()
    {
        while (scanf("%d",&N) != EOF)
        {
            init();
            un = N;
            for (int i = 1 ; i <= N ; i++)
            {
                int u,cnt;
                scanf("%d:(%d)",&u,&cnt);
                while (cnt--)
                {
                    int x;
                    scanf("%d",&x);
                    add_edge(u,x,9797);
                    add_edge(x,u,9797);
                  //  printf("%d %d
    ",u,x);
                }
            }
            printf("%d
    ",calcu() / 2);
        }
        return 0;
    }
    View Code

    还有树形DP解法

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1510;
    const int MAXM = 150010;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    int N;
    int dp[MAXN][2];
    
    int dfs(int u,int sta,int fa)
    {
        if (dp[u][sta] < INF) return dp[u][sta];
        dp[u][sta] = sta;
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (v == fa) continue;
            if (sta == 0)
                dp[u][sta] += dfs(v,1,u);
            else dp[u][sta] += min(dfs(v,1,u),dfs(v,0,u));
        }
        return dp[u][sta];
    }
    
    int main()
    {
        while (scanf("%d",&N) != EOF)
        {
            init();
            int root = 1;
            for (int i = 1 ; i <= N ; i++)
            {
                int u,cnt;
                scanf("%d:(%d)",&u,&cnt);
                if (cnt > 1) root = u;
                while (cnt--)
                {
                    int x;
                    scanf("%d",&x);
                    add_edge(u,x,9797);
                    add_edge(x,u,9797);
                  //  printf("%d %d
    ",u,x);
                }
            }
            memset(dp,0x3f,sizeof(dp));
            int ans = min(dfs(root,0,-1),dfs(root,1,-1));
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    HDU 1151 Air Raid

    一个=城镇中有n个路口和m条单项的路径,图是无环图,现在要派一些伞兵去这些成寿寺,要到达所有的路口;

    有一些或者没有伞兵可以不去那些路口,只要其他人能完成这么任务;

    每个在一个路口着陆了的伞兵可以沿着街去到其他路口;

    我们的任务就是求出去执行任务的伞兵最少可以使几个;

    二分图最小路径覆盖

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 250;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    int N,M;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&N,&M);
            init();
            while (M--)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                add_edge(u,v,9797);
            }
            printf("%d
    ",N - calcu());
        }
        return 0;
    }
    View Code

    POJ 2594 Treasure Exploration

    每个点可以走多次的最小路径覆盖

    用floyd预处理,然后一样做就行

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 510;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    int N,M;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    int G[MAXN][MAXN];
    int main()
    {
        //freopen("sample.txt","r",stdin);
        while (scanf("%d%d",&N,&M) != EOF)
        {
            if (N == 0 && M == 0) break;
            memset(G,0x3f,sizeof(G));
            for (int i = 1;  i <= M ; i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                G[u][v] = 1;
            }
            for (int k = 1; k <= N ; k++)
            {
                for (int i = 1 ; i <= N ; i++)
                {
                    for (int j = 1 ; j <= N ; j++)
                        G[i][j] = min(G[i][j],G[i][k] + G[k][j]);
                }
            }
            init();
            for (int i = 1 ; i <= N ; i++)
            {
                for (int j = 1 ; j <= N ; j++)
                {
                    if (G[i][j] < INF)
                        add_edge(i,j,9797);
                }
            }
            printf("%d
    ",N - calcu());
        }
        return 0;
    }
    View Code


    HDU 3829 Cat VS Dog

    建图方法:不管猫狗怎么样,如果2个小孩是矛盾的那么连一条边;然后求最大独立集

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 510;
    const int MAXM = MAXN * MAXN * 2;
    const int INF = 0x3f3f3f3f;
    int N,M;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 0 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    int cat,dog;
    string like[MAXN],dislike[MAXN];
    
    int main()
    {
        while (scanf("%d%d%d",&cat,&dog,&N) != EOF)
        {
            init();
            for (int i = 0 ; i < N ; i++)
            {
                cin >> like[i] >> dislike[i];
            }
            for (int i = 0 ; i < N ; i++)
            {
                for (int j = 0 ; j < N ; j++)
                {
                    if (i == j) continue;
                    if (like[i] == dislike[j] || dislike[i] == like[j])
                        add_edge(i,j,9797);
                }
            }
            printf("%d
    ",N - calcu() / 2);
        }
        return 0;
    }
    View Code

    ————————————————————————————————————————————————————————————————————————————————————————————

    二分图多重匹配

    Y部中的一个点可以连接X部的多个点。但是有连点的相关限制,求最大匹配数目的问题

    二分图的多重匹配算法的实现类似于匈牙利算法,对于集合C中的元素xi,找到一个与其相连的元素yi后,检查匈牙利算法的两个条件是否成立,若yi未被匹配,则将
    xi,yi匹配。否则,如果与yi匹配的元素已经达到上限,那么在所有与yi匹配的元素中选择一个元素,检查是否能找到一条增广路径,如果能,则让出位置,让xi与yi匹配。

    模板

    const int MAXN = 310;
    const int INF = 0x3f3f3f3f;
    bool G[MAXN][MAXN];
    int dis[MAXN][MAXN];
    bool used[MAXN];
    int linker[MAXN][MAXN];
    int num[MAXN];//Y部每个可以连接的个数,即容量
    int NX,NY;
    int K,C,M;
    
    bool dfs(int u)
    {
        for (int i = 1 ; i <= NY ; i++)
        {
            if(G[u][i] && !used[i])
            {
                used[i] = true;
                if (linker[i][0] < num[i])
                {
                    linker[i][++linker[i][0]] = u;
                    return true;
                }
                else
                {
                    for (int j = 1 ; j <= num[i] ; j++)
                    {
                        if (dfs(linker[i][j]))
                        {
                            linker[i][j] = u;
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    
    
    int calcu(int mid)
    {
        for (int i = 0 ; i <= NY ; i++) linker[i][0] = 0;
        int ret = 0;
        for (int i = 1 ; i <= NX ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    View Code

    POJ 2289 Jamie's Contact Groups

    给出一个图,然后让你分组,每组的个数尽量少

    二分

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 2010;
    bool G[MAXN][MAXN];
    bool used[MAXN];
    int NX,NY;
    char str[MAXN];
    int cnt[MAXN];
    int linker[MAXN][MAXN];
    
    bool dfs(int u,int mid)
    {
        for (int i = 0 ; i < NY ; i++)
        {
            if (G[u][i] && !used[i])
            {
                used[i] = true;
                if (linker[i][0] < mid)
                {
                    linker[i][++linker[i][0]] = u;
                    return true;
                }
                for (int j = 1 ; j <= linker[i][0] ; j++)
                {
                    if (dfs(linker[i][j],mid))
                    {
                        linker[i][j] = u;
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
    bool calcu(int mid)
    {
        int ret = 0;
        for (int i = 0 ; i < NY ; i++) linker[i][0] = 0;
        for (int i = 0 ; i < NX ; i++)
        {
            memset(used,false,sizeof(used));
            if (!dfs(i,mid)) return false;
        }
        return true;
    }
    
    int main()
    {
        int N,M;
        while (scanf("%d%d",&N,&M) != EOF)
        {
            if(N == 0 && M == 0) break;
            NX = N;
            NY = M;
            memset(G,false,sizeof(G));
            for (int i = 0 ; i < NX ; i++)
            {
                char ch;
                int x;
                scanf("%s",str);
                while(scanf("%d%c",&x,&ch) != EOF)
                {
                    G[i][x] = true;
                    if(ch == '
    ') break;
                }
            }
            //for (int i = 1 ; i <= 3 ; i++) printf("%d",calcu(i));
            int L = 0,R = NX;
            int ans;
            while (L <= R)
            {
                int mid = (L + R) / 2;
                if (calcu(mid))
                {
                    R = mid - 1;
                    ans = mid;
                }
                else L = mid + 1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    在一中网络流最大流写法

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 4010;
    const int MAXM = MAXN * 500;
    const int INF = 0x3f3f3f3f;
    vector<pair<int,int> >res;
    struct Edge
    {
        int u,v,next;
        int cap,flow;
    }edge[MAXM];
    int head[MAXN],tot;
    int gap[MAXN],dep[MAXN],cur[MAXN];
    int N,M;
    char str[MAXN];
    
    void init()
    {
        memset(head,-1,sizeof(head));
        tot = 0;
    }
    
    void add_edge(int u,int v,int cap,int rcap = 0)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].cap = cap;
        edge[tot].flow = 0;
        edge[tot].next = head[u];
        head[u] = tot++;
    
        edge[tot].u = v;
        edge[tot].v = u;
        edge[tot].cap = rcap;
        edge[tot].flow = 0;
        edge[tot].next = head[v];
        head[v] = tot++;
    }
    
    int Q[MAXN];
    void BFS(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        memset(gap,0,sizeof(gap));
        gap[0] = 1;
        int front = 0 ,rear = 0;
        dep[ed] = 0;
        Q[rear++] = ed;
        while (front < rear)
        {
            int u = Q[front++];
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                int v = edge[i].v;
                if (dep[v] != -1) continue;
                Q[rear++] = v;
                dep[v] = dep[u] + 1;
                gap[dep[v]]++;
            }
        }
    }
    
    int S[MAXN];
    int sap(int st,int ed,int N)
    {
        BFS(st,ed);
        memcpy(cur,head,sizeof(head));
        int top = 0;
        int u = st;
        int ans = 0;
        while (dep[st] < N)
        {
            if (u == ed)
            {
                int Min = INF;
                int inser;
                for (int i = 0 ; i < top ; i++)
                {
                    if (Min > edge[S[i]].cap - edge[S[i]].flow)
                    {
                        Min = edge[S[i]].cap - edge[S[i]].flow;
                        inser = i;
                    }
                }
                for (int i = 0 ; i < top ; i++)
                {
                    edge[S[i]].flow += Min;
                    edge[S[i] ^ 1].flow -=Min;
                }
                ans += Min;
                top = inser;
                u = edge[S[top] ^ 1].v;
                continue;
            }
            bool flag = false;
            int v;
            for (int i = cur[u] ; i != -1 ; i = edge[i].next)
            {
                v = edge[i].v;
                if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
                {
                    flag = true;
                    cur[u] = i;
                    break;
                }
            }
            if(flag)
            {
                S[top++] = cur[u];
                u = v;
                continue;
            }
            int Min = N;
            for (int i = head[u] ; i != -1 ; i = edge[i].next)
            {
                if (edge[i].cap - edge[i].flow && dep[edge[i].v] < Min)
                {
                    Min = dep[edge[i].v];
                    cur[u] = i;
                }
            }
            gap[dep[u]]--;
            if (!gap[dep[u]]) return ans;
            dep[u] = Min + 1;
            gap[dep[u]]++;
            if (u != st) u = edge[S[--top] ^ 1].v;
        }
        return ans;
    }
    
    
    bool calcu(int mid)
    {
        init();
        int source = N + M,target = N + M + 1;
        for (int i = 0 ; i < M ; i++)
            add_edge(source,i,mid);
        for (int i = 0 ; i < N ; i++)
            add_edge(M + i,target,1);
        for (int i = 0 ; i < (int)res.size() ; i++)
        {
            add_edge(res[i].second,res[i].first + M,1);
        }
        int ret = sap(source,target,N + M + 2);
        if(ret < N) return false;
        return true;
    }
    
    int main()
    {
        while (scanf("%d%d",&N,&M) != EOF)
        {
            if(N == 0 && M == 0) break;
            res.clear();
            for (int i = 0 ; i < N ; i++)
            {
                char ch;
                int x;
                scanf("%s",str);
                while(scanf("%d%c",&x,&ch) != EOF)
                {
                    res.push_back(make_pair(i,x));
                    if(ch == '
    ') break;
                }
            }
           // for (int i = 1 ; i <= 3 ; i++) printf("%d",calcu(i));
           // puts("");
            int L = 0,R = N;
            int ans;
            while (L <= R)
            {
                int mid = (L + R) / 2;
                if (calcu(mid))
                {
                    R = mid - 1;
                    ans = mid;
                }
                else L = mid + 1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    POJ 2112 Optimal Milking

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 310;
    const int INF = 0x3f3f3f3f;
    bool G[MAXN][MAXN];
    int dis[MAXN][MAXN];
    bool used[MAXN];
    int linker[MAXN][MAXN];
    int num[MAXN];
    int NX,NY;
    int K,C,M;
    
    bool dfs(int u)
    {
        for (int i = 1 ; i <= NY ; i++)
        {
            if(G[u][i] && !used[i])
            {
                used[i] = true;
                if (linker[i][0] < M)
                {
                    linker[i][++linker[i][0]] = u;
                    return true;
                }
                else
                {
                    for (int j = 1 ; j <= M ; j++)
                    {
                        if (dfs(linker[i][j]))
                        {
                            linker[i][j] = u;
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    
    bool calcu(int mid)
    {
        memset(G,false,sizeof(G));
        for (int i = K + 1 ; i <= C + K ; i++)
        {
            int l = i - K;
            for (int j = 1 ; j <= K; j++)
            {
                int r = j;
                if (dis[i][j] <= mid)
                    G[l][r] = true;
            }
        }
        for (int i = 0 ; i <= NY ; i++) linker[i][0] = 0;
        int ret = 0;
        for (int i = 1 ; i <= NX ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        if (ret < C) return false;
        return true;
    }
    
    int main()
    {
        while (scanf("%d%d%d",&K,&C,&M) != EOF)
        {
            for (int i = 1 ; i <= K + C ; i++)
                for (int j = 1 ; j <= K + C ; j++)
            {
                    scanf("%d",&dis[i][j]);
                    if(i != j && dis[i][j] == 0) dis[i][j] = INF;
            }
            for (int k = 1 ; k <= K + C ; k++)
            {
                for (int i = 1 ; i <= K + C ; i++)
                    for (int j = 1 ; j <= K + C ; j++)
                        dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
            }
            NX = C;
            NY = K;
            int L = 0 ,R = INF;
            int ans;
           // for (int i = 1 ; i <= 3 ; i++)printf("%d",calcu(i));puts("");
            while (L <= R)
            {
                int mid = (L + R) / 2;
                if (calcu(mid))
                {
                    ans = mid;
                    R = mid - 1;
                }
                else L = mid + 1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    POJ 3189 Steady Cow Assignment

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 3010;
    const int INF = 0x3f3f3f3f;
    int dis[MAXN][MAXN];
    bool used[MAXN];
    int linker[MAXN][MAXN];
    int num[MAXN];
    int NX,NY;
    int N,B,L,R;
    int love[MAXN][MAXN];
    
    
    bool dfs(int u)
    {
        for (int i = 1 ; i <= NY ; i++)
        {
            if(love[u][i] >= L && love[u][i] <= R && !used[i])
            {
                used[i] = true;
                if (linker[i][0] < num[i])
                {
                    linker[i][++linker[i][0]] = u;
                    return true;
                }
                else
                {
                    for (int j = 1 ; j <= num[i] ; j++)
                    {
                        if (dfs(linker[i][j]))
                        {
                            linker[i][j] = u;
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    
    bool calcu()
    {
        for (int i = 0 ; i <= NY ; i++) linker[i][0] = 0;
        for (int i = 1 ; i <= NX ; i++)
        {
            memset(used,false,sizeof(used));
            if (!dfs(i)) return false;
        }
        return true;
    }
    
    int main()
    {
        while (scanf("%d%d",&N,&B) != EOF)
        {
            for (int i = 1 ; i <= N ; i++)
            {
                for (int j = 1 ; j <= B ; j++)
                {
                    int x;
                    scanf("%d",&x);
                    love[i][x] = j;
                }
            }
            for (int i = 1 ; i <= B ; i++) scanf("%d",&num[i]);
            NX = N;
            NY = B;
            L = 1; R = 1;
            int ans = INF;
            while (L <= R && R <= B)
            {
                if (calcu())
                {
                    ans = min(ans,R - L + 1);
                    L++;
                }
                else R++;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    ————————————————————————————————————————————————————————————————————————————————————————————

    最大权KM匹配  这2道题都比较简单

    模板:点从0开始编号

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 3010;
    const int INF = 0x3f3f3f3f;
    typedef int type;
    int nx,ny;
    type g[MAXN][MAXN];
    int linker[MAXN];
    type lx[MAXN],ly[MAXN];
    type slack[MAXN];
    bool visx[MAXN],visy[MAXN];
    bool dfs(int x)
    {
        visx[x] = true;
        for (int y = 0 ; y < ny ; y++)
        {
            if (visy[y]) continue;
            type tmp = lx[x] + ly[y] - g[x][y];
            if (tmp == 0)
            {
                visy[y] = true;
                if (linker[y] == -1 || dfs(linker[y]))
                {
                    linker[y] = x;
                    return true;
                }
            }
            else if (slack[y] > tmp)
                slack[y] = tmp;
        }
        return false;
    }
    
    type KM()
    {
        memset(linker,-1,sizeof(linker));
        for (int i = 0 ;  i < MAXN ; i++) ly[i] = 0.0;
        for (int i = 0 ; i < nx ; i++)
        {
            lx[i] = -INF;
            for (int j = 0 ; j < ny ; j++)
                if (g[i][j] - lx[i] > 0)
                    lx[i] = g[i][j];
        }
        for (int x = 0 ; x < nx ; x++)
        {
            for (int i = 0 ; i < ny ; i++) slack[i] = INF;
            while (true)
            {
                memset(visx,false,sizeof(visx));
                memset(visy,false,sizeof(visy));
                if (dfs(x)) break;
                type d = INF;
                for (int i = 0 ; i < ny ; i++)
                {
                    if (!visy[i] && d - slack[i] > 0)
                        d = slack[i];
                }
                for (int i = 0 ; i < nx ; i++)
                {
                    if (visx[i])
                        lx[i] -= d;
                }
                for (int i = 0 ; i < ny ; i++)
                {
                    if (visy[i]) ly[i] += d;
                    else slack[i] -= d;
                }
            }
        }
        type ret = 0;
        for (int i = 0 ; i < ny ; i++)
            if (linker[i] != -1) ret += g[linker[i]][i];
        return ret;
    }
    
    int main()
    {
        int N;
        while (scanf("%d",&N) != EOF)
        {
            nx = N;
            ny = N;
            for (int i = 0 ; i < N ; i++)
                for (int j = 0 ; j < N ; j++) scanf("%d",&g[i][j]);
            printf("%d
    ",KM());
        }
        return 0;
    }
    View Code


    HDU 3488 Tour 最小权匹配+建图

    每个点都在一个有向环内,那么对于每个环内的点,他的出度等于入度等于1

    那么就可以拆点,一个入点,一个出点,然后就直接求最小权匹配

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 3010;
    const int INF = 0x3f3f3f3f;
    typedef int type;
    int nx,ny;
    type g[MAXN][MAXN];
    int linker[MAXN];
    type lx[MAXN],ly[MAXN];
    type slack[MAXN];
    bool visx[MAXN],visy[MAXN];
    bool dfs(int x)
    {
        visx[x] = true;
        for (int y = 0 ; y < ny ; y++)
        {
            if (visy[y]) continue;
            type tmp = lx[x] + ly[y] - g[x][y];
            if (tmp == 0)
            {
                visy[y] = true;
                if (linker[y] == -1 || dfs(linker[y]))
                {
                    linker[y] = x;
                    return true;
                }
            }
            else if (slack[y] > tmp)
                slack[y] = tmp;
        }
        return false;
    }
    
    type KM()
    {
        memset(linker,-1,sizeof(linker));
        for (int i = 0 ;  i < MAXN ; i++) ly[i] = 0.0;
        for (int i = 0 ; i < nx ; i++)
        {
            lx[i] = -INF;
            for (int j = 0 ; j < ny ; j++)
                if (g[i][j] - lx[i] > 0)
                    lx[i] = g[i][j];
        }
        for (int x = 0 ; x < nx ; x++)
        {
            for (int i = 0 ; i < ny ; i++) slack[i] = INF;
            while (true)
            {
                memset(visx,false,sizeof(visx));
                memset(visy,false,sizeof(visy));
                if (dfs(x)) break;
                type d = INF;
                for (int i = 0 ; i < ny ; i++)
                {
                    if (!visy[i] && d - slack[i] > 0)
                        d = slack[i];
                }
                for (int i = 0 ; i < nx ; i++)
                {
                    if (visx[i])
                        lx[i] -= d;
                }
                for (int i = 0 ; i < ny ; i++)
                {
                    if (visy[i]) ly[i] += d;
                    else slack[i] -= d;
                }
            }
        }
        type ret = 0;
        for (int i = 0 ; i < ny ; i++)
            if (linker[i] != -1) ret += g[linker[i]][i];
        return -ret;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            int N,M;
            scanf("%d%d",&N,&M);
            for (int i = 0 ; i <= N ; i++)
                for (int j = 0 ; j <= N ; j++) g[i][j] = -INF;
            nx = ny = N;
            for (int i = 0 ; i < M ; i++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                u--;
                v--;
                g[u][v] = max(g[u][v],-w);
            }
            printf("%d
    ",KM());
        }
        return 0;
    }
    View Code

    ————————————————————————————————————————————————————————————————————————————————————————————

    一般图匹配带花树

    复制粘贴一下。我也不太懂。弱B

    来自

    http://fanhq666.blog.163.com/blog/static/8194342620120304463580/

    在北京冬令营的时候,yby提到了“带花树开花”算法来解非二分图的最大匹配。

    于是,我打算看看这是个什么玩意。其实之前,我已经对这个算法了解了个大概,但是。。。真的不敢去写。
    有一个叫Galil Zvi的人(应该叫计算机科学家),写了篇论文:
    Efficient Algorithms for Finding Maximal Matching in Graphs
    (如果你在网上搜不到,可以:http://builtinclz.abcz8.com/art/2012/Galil%20Zvi.pdf
    这篇论文真神啊,它解决了4个问题:
    (一般图+二分图)的(最大匹配+最大权匹配)问题。
    算法的思想、故事,请自己看论文吧。
    这个论文告诉了我们很多有趣的东西,例如:
     用Dinic实现的二分图匹配的时间复杂度其实是O(M*N^0.5),这也许能够解释为什么一般网络流算法比Hungry要快了。
    另外,带花树算法的正确性的证明比较困难;而其时间复杂度是可以做到O(M*N^0.5)的,不过要详细实现,那么就快能到“ACM最长论文奖”了。
     
    我写了一个实例代码:

    http://builtinclz.abcz8.com/art/2012/ural1099.cpp

    没错,这是用来解决URAL 1099 Work Schedule那题的。时间复杂度是O(N^3)

    简述一下“带花树”算法吧:
    它的核心思想还是找增广路。假设已经匹配好了一堆点,我们从一个没有匹配的节点s开始,使用BFS生成搜索树。每当发现一个节点u,如果u还没有被匹配,那么就可以进行一次成功的增广;否则,我们就把节点u和它的配偶v一同接到树上,之后把v丢进队列继续搜索。我们给每个在搜索树上的点一个类型:S或者T。当u把它的配偶v扔进队列的时候,我们把u标记为T型,v标记为S型。于是,搜索树的样子是这样的:
           s
          /  
             
         |    |
         c    d
            
           u j
        | |  | |
        i j  v k
    其中,黑色竖线相连的两个点是已经匹配好的,蓝色斜线表示两个点之间有边,但是没有配对。T型的用红色,S型的用黑色。
     
    这里有个小问题:一个S型点d在某一步扩展的时候发现了点u,如果u已经在搜索树上了(即,出现了环),怎么办?
    我们规定,如果u的类型是T型,就无视这次发现;(这意味着我们找到了一个长度为偶数的环,直接无视)
           s
          /  
             
         |    |
         c    d   如果连出来的边是指向T型点的,就无视这个边。
            
           
        | |    |
        i j    k
    否则,我们找到了一个长度为奇数的环,就要进行一次“缩花”的操作!所谓缩花操作,就是把这个环缩成一个点。
           s
          /  
             
         |    |
         c    d
            
            
        | |   |
        i u<-+ k
    这个图缩花之后变成了5个点(一个大点,或者叫一朵花,加原来的4个点):
    缩点完成之后,还要把原来环里面的T型点统统变成S型点,之后扔到队列里去。
      +-------------+
      |             |
      |     s       |
      |    /  \     
      |           
      |   |    |    |   现在是一个点了!还是一个S点。
      |   c    d    |
      |     / \   
    +-|--  --u  ---|---+
    | |             |   |
    | |             |   |
    | |             |   |
    | +-------------+   |
    |                   |
    e                   g
    |                   |
    i                   k
    为什么能缩成一个点呢?我们看一个长度为奇数的环(例如上图中的s-b-d-u-f-c-a-),如果我们能够给它中的任意一个点找一个出度(配偶),那么环中的其他点正好可以配成对,这说明,每个点的出度都是等效的。例如,假设我们能够给图中的点d另找一个配偶(例如d'好了),那么,环中的剩下6个点正好能配成3对,一个不多,一个不少(算上d和d'一共4对刚刚好)。
    a-s-b-dd'         a s-b d-d'
     \    |       =>    \     
      cf-u              c f-u
    这就是我们缩点的思想来源。有一个劳苦功高的计算机科学家证明了:缩点之前和缩点之后的图是否有增广路的情况是相同的。
    缩起来的点又叫一朵花(blossom).
    注意到,组成一朵花的里面可能嵌套着更小的花。
     
    当我们最终找到一条增广路的时候,要把嵌套着的花层层展开,还原出原图上的增广路出来。
     
    嗯,现在你对实现这个算法有任何想法吗?
    天啊,还要缩点……写死谁。。。。。。
    我一开始也是这么想的。
    我看了一眼网上某个大牛的程序,之后结合自己的想法,很努力地写出了一个能AC的版本。
    实现的要点有什么呢?
    首先,我们不“显式”地表示花。我们记录一个Next数组,表示最终增广的时候的路径上的后继。同时,我们维护一个并查集,表示每个点现在在以哪个点为根的花里(一个花被缩进另一朵花之后就不算花了)。还要记录每个点的标记。
    主程序是一段BFS。对于每个由x发展出来的点y,分4种情况讨论:
    1。xy是配偶(不说夫妻,这是非二分图。。。)或者xy现在是一个点(在一朵花里):直接无视
    2。y是T型点:直接无视
    3。y目前单身:太好了,进行增广!
    4。y是一个S型点:缩点!缩点!
    缩点的时候要进行的工作:
    1。找x和y的LCA(的根)p。找LCA可以用各种方法。。。直接朴素也行。
    2。在Next数组中把x和y接起来(表示它们形成环了!)
    3。从x、y分别走到p,修改并查集使得它们都变成一家人,同时沿路把Next数组接起来。
     
    Next数组很奇妙。每时每刻,它实际形成了若干个挂在一起的双向链表来表示一朵花内部的走法。
         ----
        /    \--+
        |    |   |
        |    |--+
            
       ----------
      /          \
    +-            --+
    |               |
    |               |
    +----s  ------+     
     
     
     
    有权图的最大匹配怎么做?
    看论文吧。。。用类似KM的方法,不过,是给每个花再来一个权值。真的很复杂。。。
    有一个人写了代码,好像是GPL许可证。。。你最好想办法搜到它的网站来看看版权的问题;总之,我先贴出来:

    URAL 1099 模板题

    给出一个图,问你最多匹配几个点,输出匹配点

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 300;
    int N; //点的个数,点的编号从1到N
    bool Graph[MAXN][MAXN];
    int Match[MAXN];
    bool InQueue[MAXN],InPath[MAXN],InBlossom[MAXN];
    int Head,Tail;
    int Queue[MAXN];
    int Start,Finish;
    int NewBase;
    int Father[MAXN],Base[MAXN];
    int Count;//匹配数,匹配对数是Count/2
    
    void CreateGraph()
    {
        int u,v;
        memset(Graph,false,sizeof(Graph));
        scanf("%d",&N);
        while(scanf("%d%d",&u,&v) == 2)
        {
            Graph[u][v] = Graph[v][u] = true;
        }
    }
    
    void Push(int u)
    {
        Queue[Tail] = u;
        Tail++;
        InQueue[u] = true;
    }
    
    int Pop()
    {
        int res = Queue[Head];
        Head++;
        return res;
    }
    
    int FindCommonAncestor(int u,int v)
    {
        memset(InPath,false,sizeof(InPath));
        while(true)
        {
            u = Base[u];
            InPath[u] = true;
            if(u == Start) break;
            u = Father[Match[u]];
        }
        while(true)
        {
            v = Base[v];
            if(InPath[v])break;
            v = Father[Match[v]];
        }
        return v;
    }
    
    void ResetTrace(int u)
    {
        int v;
        while(Base[u] != NewBase)
        {
            v = Match[u];
            InBlossom[Base[u]] = InBlossom[Base[v]] = true;
            u = Father[v];
            if(Base[u] != NewBase) Father[u] = v;
        }
    }
    
    void BloosomContract(int u,int v)
    {
        NewBase = FindCommonAncestor(u,v);
        memset(InBlossom,false,sizeof(InBlossom));
        ResetTrace(u);
        ResetTrace(v);
        if(Base[u] != NewBase) Father[u] = v;
        if(Base[v] != NewBase) Father[v] = u;
        for(int tu = 1; tu <= N; tu++)
            if(InBlossom[Base[tu]])
        {
                Base[tu] = NewBase;
                if(!InQueue[tu]) Push(tu);
        }
    }
    
    void FindAugmentingPath()
    {
        memset(InQueue,false,sizeof(InQueue));
        memset(Father,0,sizeof(Father));
        for(int i = 1; i <= N; i++)
            Base[i] = i;
        Head = Tail = 1;
        Push(Start);
        Finish = 0;
        while(Head < Tail)
        {
            int u = Pop();
            for(int v = 1; v <= N; v++)
                if(Graph[u][v] && (Base[u] != Base[v]) && (Match[u] != v))
                {
                    if((v == Start) || ((Match[v] > 0) && Father[Match[v]] > 0))
                        BloosomContract(u,v);
                    else if(Father[v] == 0)
                    {
                        Father[v] = u;
                        if(Match[v] > 0)
                            Push(Match[v]);
                        else
                        {
                            Finish = v;
                            return;
                        }
                    }
                }
        }
    }
    
    void AugmentPath()
    {
        int u,v,w;
        u = Finish;
        while(u > 0)
        {
            v = Father[u];
            w = Match[v];
            Match[v] = u;
            Match[u] = v;
            u = w;
        }
    }
    
    void Edmonds()
    {
        memset(Match,0,sizeof(Match));
        for(int u = 1; u <= N; u++)
            if(Match[u] == 0)
            {
                Start = u;
                FindAugmentingPath();
                if(Finish > 0)AugmentPath();
            }
    }
    
    void PrintMatch()
    {
        Count = 0;
        for(int u = 1; u <= N; u++)
            if(Match[u] > 0)
                Count++;
        printf("%d
    ",Count);
        for(int u = 1; u <= N; u++)
            if(u < Match[u])
                printf("%d %d
    ",u,Match[u]);
    }
    
    int main()
    {
        CreateGraph();//建图
        Edmonds();//进行匹配
        PrintMatch();//输出匹配数和匹配
        return 0;
    }
    View Code

    HDU 4687 Boke and Tsukkomi
    暴力删边,计算新图的最大匹配如果小于原图匹配-1.就不是最大匹配里的边。

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 70;
    int N; //点的个数,点的编号从1到N
    bool Graph[MAXN][MAXN];
    int Match[MAXN];
    bool InQueue[MAXN],InPath[MAXN],InBlossom[MAXN];
    int Head,Tail;
    int Queue[MAXN];
    int Start,Finish;
    int NewBase;
    int Father[MAXN],Base[MAXN];
    int Count;//匹配数,匹配对数是Count/2
    
    void CreateGraph()
    {
        int u,v;
        memset(Graph,false,sizeof(Graph));
        scanf("%d",&N);
        while(scanf("%d%d",&u,&v) == 2)
        {
            Graph[u][v] = Graph[v][u] = true;
        }
    }
    
    void Push(int u)
    {
        Queue[Tail] = u;
        Tail++;
        InQueue[u] = true;
    }
    
    int Pop()
    {
        int res = Queue[Head];
        Head++;
        return res;
    }
    
    int FindCommonAncestor(int u,int v)
    {
        memset(InPath,false,sizeof(InPath));
        while(true)
        {
            u = Base[u];
            InPath[u] = true;
            if(u == Start) break;
            u = Father[Match[u]];
        }
        while(true)
        {
            v = Base[v];
            if(InPath[v])break;
            v = Father[Match[v]];
        }
        return v;
    }
    
    void ResetTrace(int u)
    {
        int v;
        while(Base[u] != NewBase)
        {
            v = Match[u];
            InBlossom[Base[u]] = InBlossom[Base[v]] = true;
            u = Father[v];
            if(Base[u] != NewBase) Father[u] = v;
        }
    }
    
    void BloosomContract(int u,int v)
    {
        NewBase = FindCommonAncestor(u,v);
        memset(InBlossom,false,sizeof(InBlossom));
        ResetTrace(u);
        ResetTrace(v);
        if(Base[u] != NewBase) Father[u] = v;
        if(Base[v] != NewBase) Father[v] = u;
        for(int tu = 1; tu <= N; tu++)
            if(InBlossom[Base[tu]])
        {
                Base[tu] = NewBase;
                if(!InQueue[tu]) Push(tu);
        }
    }
    
    void FindAugmentingPath()
    {
        memset(InQueue,false,sizeof(InQueue));
        memset(Father,0,sizeof(Father));
        for(int i = 1; i <= N; i++)
            Base[i] = i;
        Head = Tail = 1;
        Push(Start);
        Finish = 0;
        while(Head < Tail)
        {
            int u = Pop();
            for(int v = 1; v <= N; v++)
                if(Graph[u][v] && (Base[u] != Base[v]) && (Match[u] != v))
                {
                    if((v == Start) || ((Match[v] > 0) && Father[Match[v]] > 0))
                        BloosomContract(u,v);
                    else if(Father[v] == 0)
                    {
                        Father[v] = u;
                        if(Match[v] > 0)
                            Push(Match[v]);
                        else
                        {
                            Finish = v;
                            return;
                        }
                    }
                }
        }
    }
    
    void AugmentPath()
    {
        int u,v,w;
        u = Finish;
        while(u > 0)
        {
            v = Father[u];
            w = Match[v];
            Match[v] = u;
            Match[u] = v;
            u = w;
        }
    }
    
    void Edmonds()
    {
        memset(Match,0,sizeof(Match));
        for(int u = 1; u <= N; u++)
            if(Match[u] == 0)
            {
                Start = u;
                FindAugmentingPath();
                if(Finish > 0)AugmentPath();
            }
    }
    
    int PrintMatch()
    {
        Edmonds();
        Count = 0;
        for(int u = 1; u <= N; u++)
            if(Match[u] > 0)
                Count++;
        return Count / 2;
    }
    
    bool g[MAXN][MAXN];
    vector<pair<int,int> >res;
    int main()
    {
        int M;
        while (scanf("%d%d",&N,&M) != EOF)
        {
            res.clear();
            memset(g,false,sizeof(g));
            memset(Graph,false,sizeof(Graph));
            for (int i = 1 ; i <= M ; i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                res.push_back(make_pair(u,v));
                g[u][v] = g[v][u] = true;
                Graph[u][v] = Graph[v][u] = true;
            }
            int tot = PrintMatch();
            vector<int>ans;
            for (int i = 0 ; i < M ; i++)
            {
                int u = res[i].first;
                int v = res[i].second;
                memcpy(Graph,g,sizeof(g));
                for (int j = 1 ; j <= N ; j++)
                   Graph[u][j] = Graph[j][u] = Graph[v][j] = Graph[j][v] = false;
                int ret = PrintMatch();
                if (ret < tot - 1) ans.push_back(i + 1);
            }
            printf("%d
    ",ans.size());
            int sz = ans.size();
            for (int i = 0 ; i < sz ; i++)
            {
                printf("%d",ans[i]);
                if (i < sz - 1) putchar(' ');
            }
            puts("");
        }
        return 0;
    }
    View Code

    UVALIVE 5962 Strongly Connected Chemicals

    题意:一堆阴离子阳离子,给出阴阳离子吸引关系。求最大的集合满足所有阳离子可以吸附所有阴离子。但是有一个限制最大的集合至少有一对阴阳离子

    solotion:很容易想到建立补图求最大独立及。但是注意无法满足条件 。于是就暴力枚举一定在图里面的阴阳离子。

    假设枚举a b 然后找到所有的和a可以共存的阴离子(设为x集合)以及和b共存的阳离子(设为y集合) 

    现在只需求x集合中和y集合中最多有多少个离子可以共存 这个求最大独立集就行了 枚举所有的a b 取最大值

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 110;
    char G[MAXN][MAXN];
    int N,M;
    const int MAXM = 100010;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int u,v,next;
        int w;
    }edge[MAXM];
    int head[MAXN],tot;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void add_edge(int u,int v,int w)
    {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool used[MAXN];
    int linker[MAXN];
    bool dfs(int u)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (!used[v])
            {
                used[v] = true;
                if (linker[v] == -1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0 ;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= N ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    int main() {
        int T,kase = 1;
        scanf("%d",&T);
        while (T--) {
            scanf("%d%d",&N,&M);
            for (int i = 1 ; i <= N ; i++) scanf("%s",G[i] + 1);
            int ans = 0;
            for (int i = 1 ; i <= N ; i++) {
                for (int j = 1 ; j <= M ; j++) {
                    if (G[i][j] == '0') continue;
                    int cnt1 = 0,cnt2 = 0;
                    for (int p = 1 ; p <= N ; p++) if (G[p][j] == '1') cnt1++;
                    for (int q = 1 ; q <= M ; q++) if (G[i][q] == '1') cnt2++;
                    init();
                    for (int p = 1 ; p <= N ; p++) {
                        if (G[p][j] == '0') continue;
                        for (int  q = 1 ; q <= M ; q++) {
                            if (G[i][q] == '1' && G[p][q] == '0')
                                add_edge(p,q,97);
                        }
                    }
                    ans = max(ans,cnt1 + cnt2 - calcu());
                }
            }
            printf("Case %d: %d
    ", kase++, ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    数据结构——算法之(029)( 字符串原地压缩)
    hihoCoder #1174:拓扑排序&#183;一
    POJ 3026 Borg Maze
    Remove Duplicates from Sorted List II--LeetCode
    mach-o格式分析
    otool -l 可执行文件结构
    mach-o可执行文件结果
    ios 编译版本 最低版本 运行版本 动态链接库
    关于__IPHONE_OS_VERSION_MAX_ALLOWED和__IPHONE_OS_VERSION_MIN_ALLOWED的用法
    OO真经——关于面向对象的哲学体系及科学体系的探讨(下)
  • 原文地址:https://www.cnblogs.com/Commence/p/4921675.html
Copyright © 2011-2022 走看看