匈牙利算法

匈牙利算法的基本知识:

百度百科:

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

你可能感兴趣的:(算法)