匈牙利算法

匈牙利算法的基本知识:

百度百科:

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

posted @ 2012-02-15 14:21  skyming  阅读(1046)  评论(1编辑  收藏  举报