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;  
        }  
  • 相关阅读:
    边框的各种样式
    内容溢出显示省略号
    UNIAPP开发注意事项
    css文本的三条线 删除线 下划线 上划线
    防抖截流
    浏览器窗口改变触发的函数
    ES5数组方法
    弹性布局
    ubuntu16.04 安装adb
    git clone
  • 原文地址:https://www.cnblogs.com/zufezzt/p/4847237.html
Copyright © 2011-2022 走看看