zoukankan      html  css  js  c++  java
  • 匈牙利算法

    匈牙利算法的基本知识:

    百度百科:

    http://baike.baidu.com/view/501092.htm

    维基百科: 这里面有邻接矩阵的模拟图

    http://en.wikipedia.org/wiki/Hungarian_algorithm

    二分图性质总结

    http://www.cnblogs.com/jffifa/archive/2011/12/26/2302480.html

     http://blog.csdn.net/leolin_/article/details/7199688

    性质的证明:

    http://wenku.baidu.com/view/d1b1b165783e0912a2162a9c.html

    (v^3) 模版

    View Code
    #include <stdio.h>
    #include <string.h>
    int n1, n2, m, ans;
    int result[101]; //记录V2中的点匹配的点的编号
    bool state [101]; //记录V2中的每个点是否被搜索过
    bool data[101][101];//邻接矩阵 true代表有边相连
    void init()
    {
        int t1, t2;
        memset(data, 0, sizeof(data));
        memset(result, 0, sizeof(result));
        ans = 0;
        scanf("%d%d%d", &n1, &n2, &m);
        for (int i = 1; i <= m; i++)
        {
         scanf("%d%d", &t1, &t2);k
         data[t1][t2] = true;
        }
        return;
    }
    bool find(int a)
    {
        for (int i = 1; i <= n2; i++)
        {
           if (data[a][i] == 1 && !state[i]) //如果节点i与a相邻并且未被查找过
            {
              state[i] = true; //标记i为已查找过
              if (result[i] == 0 //如果i未在前一个匹配M中
              || find(result[i])) //i在匹配M中,但是从与i相邻的节点出发可以有增广路
              {
                result[i] = a; //记录查找成功记录
                return true; //返回查找成功
              }
             }
        }
        return false;
    }
    int main()
    {
        init();
        for (int i = 1; i <= n1; i++)
        {
           memset(state, 0, sizeof(state)); //清空上次搜索时的标记
           if (find(i)) ans++; //从节点i尝试扩展
        }
        printf("%d\n", ans);
    return 0;
    }

    (VE) 模版

    View Code
    View Code 
    
    #include <iostream>
    #include <stdio.h>
    #include <memory.h>
    #include <vector>
    using namespace std;
    const int N = 1505;
    int pre[N];
    bool flag[N];
    vector<int> map[N];
    int n;
    
    int find(int cur)
    {
        int i, k;
        for(i = 0; i < map[cur].size(); i++)
        {
            k = map[cur][i];
            if(!flag[k])
            {
                flag[k] = true;
                if(pre[k] == -1 || find(pre[k]))
                {
                    pre[k] = cur;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        int i, j, r, k, num, sum;
        while(scanf("%d", &n) != EOF)
        {
            memset(pre, -1, sizeof(pre));
            for(i = 0; i < n; i++) map[i].clear();
            for(i = 0; i < n; i++)
            {
                scanf("%d:(%d)", &k, &num);
                for(j = 0; j < num; j++)
                {
                    scanf("%d", &r);
                    map[k].push_back(r);    //用邻接表
                    map[r].push_back(k);    //建双向图
                }
            }
            sum = 0;
            for(i = 0; i < n; i++)
            {
                memset(flag, false, sizeof(flag));
                sum += find(i);
            }
            printf("%d\n", sum/2);
        }
    
        return 0;
    }

    题目:

    模版题:

    http://acm.hdu.edu.cn/showproblem.php?pid=2119

    View Code
    #include<stdio.h>
    #include<cstring>
    int map[105][105],n,m;
    int visit[105],result[105];
    int dfs(int u)
    {
        for(int i=0;i<m;i++)
        {
            if(map[u][i]&&!visit[i])
            {
                visit[i]=1;
                if(result[i]==-1||dfs(result[i]))
                {
                      result[i]=u;
                      return 1;
                }
    
            }
        }
        return 0;
    }
    int main()
    {
    
        while(scanf("%d",&n),n)
        {
    
            scanf("%d",&m);
            memset(result,-1,sizeof(result));
            for(int i=0;i<n;i++)
             for(int j=0;j<m;j++)
             scanf("%d",&map[i][j]);
    
             int sum=0;
            for(int i=0;i<n;i++)
            {
                memset(visit,0,sizeof(visit));
                if(dfs(i))
                sum++;
            }
            printf("%d\n",sum);
        }
    }

    http://poj.org/problem?id=1274

    View Code

    http://poj.org/problem?id=2239

    poj 3041  Asteroids

    用x 轴的点集和y 轴的点集匹配 ,求最大匹配即为最小点覆盖

    View Code
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=1083

    求完美匹配 水题

    View Code
    #include<stdio.h>
    #include<cstring>
    #define N 305
    int map[N][N],n,m;
    int visit[N],result[N];
    int dfs(int u)
    {
        for(int i=1;i<=m;i++)
        {
            if(map[u][i]&&!visit[i])
            {
                visit[i]=1;
                if(result[i]==-1||dfs(result[i]))
                {
                      result[i]=u;
                      return 1;
                }
    
            }
        }
        return 0;
    }
    int main()
    {
        int t; scanf("%d",&t);
        while(t--)
        {
             scanf("%d%d",&n,&m);
             memset(map,0,sizeof(map));
             memset(result,-1,sizeof(result));
    
             for(int i=1;i<=n;i++)
             {
                 scanf("%d",&map[i][0]);
                 for(int j=1;j<=map[i][0];j++)
                 {
                      int x;
                      scanf("%d",&x);
                      map[i][x]=1;
                 }
    
             }
             int sum=0;
             for(int i=1;i<=n;i++)
             {
                memset(visit,0,sizeof(visit));
                sum+=dfs(i);
             }
             puts(sum==n? "YES":"NO");
        }
        return 0;
    }

    http://poj.org/problem?id=2536

    View Code
    #include<stdio.h>
    #include<cstring>
    #include<cmath>
    #define N 105
    int map[N][N],n,m;
    int visit[N],result[N];
    double  pos[N][2];
    int dfs(int u)
    {
        for(int i=1;i<=m;i++)
        {
    
             if(map[u][i]&&!visit[i])
              {
                visit[i]=1;
                if(result[i]==-1||dfs(result[i]))
                {
                      result[i]=u;
                      return 1;
                }
    
              }
    
    
        }
        return 0;
    }
    int main()
    {
            int t,v;
            while( scanf("%d%d%d%d",&n,&m,&t,&v)!=EOF)
            {
                memset(map,0,sizeof(map));
                memset(result,-1,sizeof(result));
                memset(pos,0,sizeof(pos));
                for(int i=1;i<=n;i++)
                {
                 double x,y;
                 scanf("%lf%lf",&pos[i][0],&pos[i][1]);
    
                }
                double road=t*v;
                for(int i=1;i<=m;i++)
                {
                    double x,y;
                    scanf("%lf%lf",&x,&y);
                    for(int j=1;j<=n;j++)
                    {
                       double dis=(x-pos[j][0])*(x-pos[j][0])+(y-pos[j][1])*(y-pos[j][1]);
                       dis=sqrt(dis);
                       if(dis<=road)
                       map[j][i]=1;
                    }
    
                }
    
               int sum=0;
               for(int i=1;i<=n;i++)
               {
                memset(visit,0,sizeof(visit));
                if(dfs(i))
                sum++;
               }
                printf("%d\n",n-sum);
            }
            return 0;
    
    }

    http://poj.org/problem?id=2771

    条件有点多,男女匹配即可

    View Code
    #include<stdio.h>
    #include<cstring>
    #include<cmath>
    #define N 505
    int map[N][N];
    int nv,na;
    int visit[N],result[N];
    struct node
    {
        int height;
        char sex;
        char mus[105],sport[105];
    }male[N],famale[N];
    int dfs(int u)
    {
        for(int i=1;i<=nv;i++)
        {
    
             if(map[u][i]&&!visit[i])
              {
                visit[i]=1;
                if(result[i]==-1||dfs(result[i]))
                {
                      result[i]=u;
                      return 1;
                }
    
              }
        }
        return 0;
    }
    int main()
    {
            int t,n;scanf("%d",&t);
            while(t--)
            {
                scanf("%d",&n);
                memset(map,0,sizeof(map));
                memset(result,-1,sizeof(result));
                na=0,nv=0;
    
                for(int i=1;i<=n;i++)
                {
                  int hei;char st;
                  scanf("%d %c",&hei,&st);
                  if(st=='M')
                  {
                      male[++na].height=hei;
                      scanf("%s %s",male[na].mus,male[na].sport);
                  }
                  else
                  {
                      famale[++nv].height=hei;
                      scanf("%s %s",famale[nv].mus,famale[nv].sport);
                  }
    
                }
                for(int i=1;i<=na;i++)
                 for(int j=1;j<=nv;j++)
                    {
                       int k=famale[j].height-male[i].height;
                       if(fabs(k)<=40&&!strcmp(male[i].mus,famale[j].mus)
                          &&strcmp(male[i].sport,famale[j].sport))
    
                         map[i][j]=1;
    
                    }
               int sum=0;
               for(int i=1;i<=na;i++)
               {
                memset(visit,0,sizeof(visit));
                sum+=dfs(i);
               }
               printf("%d\n",n-sum);
            }
            return 0;
    
    }

     提高篇:

    hdu 1054    Strategic Game

    http://acm.hdu.edu.cn/showproblem.php?pid=1054

    最小顶点覆盖 == 【最大匹配(双向建图)】/2

    View Code
    #include <iostream>
    #include <stdio.h>
    #include <memory.h>
    #include <vector>
    using namespace std;
    const int N = 1505;
    int pre[N];
    bool flag[N];
    vector<int> map[N];
    int n;
    
    int find(int cur)
    {
        int i, k;
        for(i = 0; i < map[cur].size(); i++)
        {
            k = map[cur][i];
            if(!flag[k])
            {
                flag[k] = true;
                if(pre[k] == -1 || find(pre[k]))
                {
                    pre[k] = cur;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        int i, j, r, k, num, sum;
        while(scanf("%d", &n) != EOF)
        {
            memset(pre, -1, sizeof(pre));
            for(i = 0; i < n; i++) map[i].clear();
            for(i = 0; i < n; i++)
            {
                scanf("%d:(%d)", &k, &num);
                for(j = 0; j < num; j++)
                {
                    scanf("%d", &r);
                    map[k].push_back(r);    //用邻接表
                    map[r].push_back(k);    //建双向图
                }
            }
            sum = 0;
            for(i = 0; i < n; i++)
            {
                memset(flag, false, sizeof(flag));
                sum += find(i);
            }
            printf("%d\n", sum/2);
        }
    
        return 0;
    }

     hdu  1150   Machine Schedule

    最小顶点覆盖数=最大匹配数 还要注意 0 点不要算在内 注意多组数据清零

    View Code
    #include<stdio.h>
    #include<string.h>
    #define N 110
    int map[N][N],vis[N],result[N];
    int n,m,k;
    int find(int s)
    {
        for(int i=0;i<m;i++)
        {
            if(map[s][i]&&!vis[i])
            {
                vis[i]=1;
                if(result[i]==-1||find(result[i]))
                {
                    result[i]=s;return 1;
                }
            }
        }
        return 0;
    }
    int main()
    {
        while(scanf("%d",&n),n)
        {
            memset(result,-1,sizeof(result));
            memset(map,0,sizeof(map));
            scanf("%d%d",&m,&k);
            while(k--)
            {
                int w,u,v;scanf("%d%d%d",&w,&u,&v);
                map[u][v]=1;
            }
            int sum=0;
            for(int i=0;i<n;i++)
            {
                memset(vis,0,sizeof(vis));
                sum+=find(i);
            }
            printf("%d\n",sum);
        }
    }

    poj 1466  Girls and Boys

    http://poj.org/problem?id=1466

    最大独立集 == |P| 减 【最大匹配(双向建图)】/2 ;

    View Code
    #include <iostream>
    #include <stdio.h>
    #include <memory.h>
    #include <string.h>
    #include <vector>
    using namespace std;
    const int N = 1505;
    int pre[N];
    bool flag[N];
    vector<int> map[N];
    int n;
    
    int find(int cur)
    {
        int i, k;
        for(i = 0; i < map[cur].size(); i++)
        {
            k = map[cur][i];
            if(!flag[k])
            {
                flag[k] = true;
                if(pre[k] == -1 || find(pre[k]))
                {
                    pre[k] = cur;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        int i, j, r, k, num, sum;
        while(scanf("%d", &n) != EOF)
        {
            memset(pre, -1, sizeof(pre));
            for(i = 0; i < n; i++) map[i].clear();
            for(i = 0; i < n; i++)
            {
                scanf("%d: (%d)", &k, &num);
                for(j = 0; j < num; j++)
                {
                    scanf("%d", &r);
                    map[k].push_back(r);    //用邻接表
                    map[r].push_back(k);    //建双向图
                }
            }
            sum = 0;
            for(i = 0; i < n; i++)
            {
                memset(flag, false, sizeof(flag));
                sum += find(i);
            }
            printf("%d\n", n-sum/2);
        }
    
        return 0;
    }

    hdu 1151  air raid

    最小路径覆盖 == |P| 减 【最大匹配】,适用于有向无环图【DAG图

    证明上面有连接

    View Code
    #include <iostream>
    #include <stdio.h>
    #include <memory.h>
    #include <vector>
    using namespace std;
    const int N = 1505;
    int pre[N];
    bool flag[N];
    vector<int> map[N];
    int n,m;
    
    int find(int cur)
    {
        int i, k;
        for(i = 0; i < map[cur].size(); i++)
        {
            k = map[cur][i];
            if(!flag[k])
            {
                flag[k] = true;
                if(pre[k] == -1 || find(pre[k]))
                {
                    pre[k] = cur;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        int i, r, k,sum;int cs;cin>>cs;
        while(cs--)
        {
            scanf("%d%d", &n,&m);
            memset(pre, -1, sizeof(pre));
            for(i = 1; i <= n; i++) map[i].clear();
            for(i = 1; i <= m; i++)
            {
                scanf("%d%d",&k, &r);
                map[k].push_back(r);    //用邻接表
                   //map[r].push_back(k);    //建双向图
            }
            sum = 0;
            for(i = 1; i <= n; i++)
            {
                memset(flag, false, sizeof(flag));
                sum += find(i);
            }
            printf("%d\n", n-sum);
        }
        return 0;
    }

    部分待刷题

    http://blog.csdn.net/huanglianzheng/article/details/5605771

    http://972169909-qq-com.iteye.com/blog/1154835

    http://apps.hi.baidu.com/share/detail/15415702

    http://www.ieee.org.cn/dispbbs.asp?boardID=60&ID=40964
    http://hi.baidu.com/acmost/blog/item/a484e50fe2845ec37acbe14d.html

    Just a little, maybe change the world
  • 相关阅读:
    gw经销商上传部分代码
    lib
    【转】sql server的随机函数newID()和RAND()
    【源码】仿qq记住登录信息
    关于ConfigurationManager类
    oracle 10 协议适配器错误解决办法
    配置对象数据源时,无法找到业务对象的解决办法
    private的由来,让能你很容易地区分private与protected的用法!
    大树扎根不稳,缘何不倒?
    Html服务器控件常用属性InnerHtml属性及InnerText属性的区别
  • 原文地址:https://www.cnblogs.com/skyming/p/2352562.html
Copyright © 2011-2022 走看看