zoukankan      html  css  js  c++  java
  • URAL 1099 Work scheduling 一般图的最大匹配 带花树算法(模板)

    R - Work scheduling
    Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

    Description

    There is certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to scheduled in pairs, so that each pair guards at different night. The junkyard CEO ordered you to write a program which given the guards characteristics determines the maximum amount of scheduled guards (the rest will be fired). Please note that each guard can be scheduled with only one of his colleagues and no guard can work alone.

    Input

    The first line of the input contains one number N ≤ 222 which is the amount of night guards. Unlimited number of lines consisting of unordered pairs ( ij) follow, each such pair means that guard # i and guard # j can work together, because it is possible to find uniforms that suit both of them (The junkyard uses different parts of uniforms for different guards i.e. helmets, pants, jackets. It is impossible to put small helmet on a guard with a big head or big shoes on guard with small feet). The input ends with Eof.

    Output

    You should output one possible optimal assignment. On the first line of the output write the even number C, the amount of scheduled guards. Then output C/2 lines, each containing 2 integers ( ij) that denote that i and j will work together.

    Sample Input

    inputoutput
    3
    1 2
    2 3
    1 3
    
    2
    1 2
    

    就是有n个人,之后给出若干个关系,之后求最大可以保留多少对关系,要求可以删除若干个人

    下面两个都是模板,两个模板都是可以套用的·1

    1

    #include<stdio.h>
    #include<string.h>
    #include<string.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int MAXN = 250;
    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;
    }

    (2)

        #include <cstdio>  
        #include <cstring>  
        #include <iostream>  
        #include <queue>  
        using namespace std;       
        const int N = 250;     
        // 并查集维护  
        int belong[N];  
        int findb(int x) {   
            return belong[x] == x ? x : belong[x] = findb(belong[x]);  
        }  
        void unit(int a, int b) {  
            a = findb(a);  
            b = findb(b);  
            if (a != b) belong[a] = b;  
        }  
          
        int n, match[N];  
        vector<int> e[N];  
        int Q[N], rear;  
        int next[N], mark[N], vis[N];  
        // 朴素算法求某阶段中搜索树上两点x, y的最近公共祖先r  
        int LCA(int x, int y) {  
            static int t = 0; t++;  
            while (true) {  
                if (x != -1) {  
                    x = findb(x); // 点要对应到对应的花上去  
                    if (vis[x] == t) 
                       return x;  
                    vis[x] = t;  
                    if (match[x] != -1) 
                       x = next[match[x]];  
                    else x = -1;  
                }  
                swap(x, y);  
            }  
        }  
          
        void group(int a, int p) {  
            while (a != p) {  
                int b = match[a], c = next[b];  
          
                // next数组是用来标记花朵中的路径的,综合match数组来用,实际上形成了  
                // 双向链表,如(x, y)是匹配的,next[x]和next[y]就可以指两个方向了。  
                if (findb(c) != p) next[c] = b;  
          
                // 奇环中的点都有机会向环外找到匹配,所以都要标记成S型点加到队列中去,  
                // 因环内的匹配数已饱和,因此这些点最多只允许匹配成功一个点,在aug中  
                // 每次匹配到一个点就break终止了当前阶段的搜索,并且下阶段的标记是重  
                // 新来过的,这样做就是为了保证这一点。  
                if (mark[b] == 2) mark[Q[rear++] = b] = 1;  
                if (mark[c] == 2) mark[Q[rear++] = c] = 1;  
          
                unit(a, b); unit(b, c);  
                a = c;  
            }  
        }  
          
        // 增广  
        void aug(int s) {  
            for (int i = 0; i < n; i++) // 每个阶段都要重新标记  
                next[i] = -1, belong[i] = i, mark[i] = 0, vis[i] = -1;  
            mark[s] = 1;  
            Q[0] = s; rear = 1;   
            for (int front = 0; match[s] == -1 && front < rear; front++) {  
                int x = Q[front]; // 队列Q中的点都是S型的  
                for (int i = 0; i < (int)e[x].size(); i++) {  
                    int y = e[x][i];  
                    if (match[x] == y) continue; // x与y已匹配,忽略  
                    if (findb(x) == findb(y)) continue; // x与y同在一朵花,忽略  
                    if (mark[y] == 2) continue; // y是T型点,忽略  
                    if (mark[y] == 1) { // y是S型点,奇环缩点  
                        int r = LCA(x, y); // r为从i和j到s的路径上的第一个公共节点  
                        if (findb(x) != r) next[x] = y; // r和x不在同一个花朵,next标记花朵内路径  
                        if (findb(y) != r) next[y] = x; // r和y不在同一个花朵,next标记花朵内路径  
          
                        // 将整个r -- x - y --- r的奇环缩成点,r作为这个环的标记节点,相当于论文中的超级节点  
                        group(x, r); // 缩路径r --- x为点  
                        group(y, r); // 缩路径r --- y为点  
                    }  
                    else if (match[y] == -1) { // y自由,可以增广,R12规则处理  
                        next[y] = x;  
                        for (int u = y; u != -1; ) { // 交叉链取反  
                            int v = next[u];  
                            int mv = match[v];  
                            match[v] = u, match[u] = v;  
                            u = mv;  
                        }  
                        break; // 搜索成功,退出循环将进入下一阶段  
                    }  
                    else { // 当前搜索的交叉链+y+match[y]形成新的交叉链,将match[y]加入队列作为待搜节点  
                        next[y] = x;  
                        mark[Q[rear++] = match[y]] = 1; // match[y]也是S型的  
                        mark[y] = 2; // y标记成T型  
                    }  
                }  
            }  
        }  
          
        bool g[N][N];  
        int main() {  
            scanf("%d", &n);  
            for (int i = 0; i < n; i++)  
                for (int j = 0; j < n; j++) g[i][j] = false;  
          
            // 建图,双向边  
            int x, y; while (scanf("%d%d", &x, &y) != EOF) {  
                x--, y--;  
                if (x != y && !g[x][y])  
                    e[x].push_back(y), e[y].push_back(x);  
                g[x][y] = g[y][x] = true;  
            }  
          
            // 增广匹配  
            for (int i = 0; i < n; i++) match[i] = -1;  
            for (int i = 0; i < n; i++) if (match[i] == -1) aug(i);  
          
            // 输出答案  
            int tot = 0;  
            for (int i = 0; i < n; i++) if (match[i] != -1) tot++;  
            printf("%d
    ", tot);  
            for (int i = 0; i < n; i++) if (match[i] > i)  
                printf("%d %d
    ", i + 1, match[i] + 1);  
            return 0;  
        }  
  • 相关阅读:
    2020年MongoDB 企业应用实战 基础 复制集 分片集群
    2020年Redis5.0 从入门到企业应用实战
    2020年Jumpserver1.5.8企业生产部署指南
    python单例与数据库连接池
    python 异常处理
    python 正则
    python 多线程
    python 队列
    python 闭包与装饰器
    程序员面试资源集锦
  • 原文地址:https://www.cnblogs.com/13224ACMer/p/4844922.html
Copyright © 2011-2022 走看看