zoukankan      html  css  js  c++  java
  • URAL 1099 Work Scheduling

    一般图的最大匹配  带花树开花算法

    有两个模板,一个kuangbin大神的,另一个不知道谁写的。

    #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;
    }
    #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;  
        }  
  • 相关阅读:
    hadoop再次集群搭建(3)-如何选择相应的hadoop版本
    48. Rotate Image
    352. Data Stream as Disjoint Interval
    163. Missing Ranges
    228. Summary Ranges
    147. Insertion Sort List
    324. Wiggle Sort II
    215. Kth Largest Element in an Array
    快速排序
    280. Wiggle Sort
  • 原文地址:https://www.cnblogs.com/zufezzt/p/4847237.html
Copyright © 2011-2022 走看看