hdu1150 Machine Schedule (匈牙利算法模版)

匈牙利算法本质就是一个个的匹配,对于当前的处理的对象i,假设他的匹配对象为j,但是j已经和v匹配好了,那么就让v去找找着能不能和别人匹配

v可以和别人匹配则i与j匹配,不能则i去找别人匹配

另外引入几个定义和结论:

1:最大匹配数 + 最大独立集 = n + m(n,m为二分图两边的节点数)

2:二分图的最小顶点覆盖数 = 最大匹配数

3:最小路径覆盖 = 最大独立集

最大独立集是指:求一个二分图中最大的一个点集,该点集内的点互不相连。

最小顶点覆盖是指: 在二分图中,用最少的点,让所有的边至少和一个点有关联。

最小路径覆盖是指:

对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。

最大匹配是指:

对于二分图的所有边,寻找一个子集,这个子集满足两个条件,
1:任意两条边都不依赖于同一个点。
2:让这个子集里的边在满足条件一的情况下尽量多。

 算法的证明如下:http://blog.csdn.net/yuxue_23/article/details/12224067

然后是模版:

bool find(int x){
    int i,j;
    for (j=1;j<=m;j++){    //扫描每个妹子
        if (line[x][j]==true && used[j]==false)      
        //如果有暧昧并且还没有标记过(这里标记的意思是这次查找曾试图改变过该妹子的归属问题,但是没有成功,所以就不用瞎费工夫了)
        {
            used[j]=1;
            if (girl[j]==0 || find(girl[j])) { 
                //名花无主或者能腾出个位置来,这里使用递归
                girl[j]=x;
                return true;
            }
        }
    }
    return false;
}
int main(){
for (i=1;i<=n;i++)
{
    memset(used,0,sizeof(used));    //这个在每一步中清空
    if find(i) all+=1;
}
  return 0;       
}

然后是本题代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
#define PF(x) cout << "debug: " << x << " ";
#define EL cout << endl;
#define PC(x) puts(x);
typedef long long ll;
#define CLR(x, v) sizeof (x, v, sizeof(x))
using namespace std;
const int INF = 0x5f5f5f5f;
const int  N= 1000050;
const int maxn=110;
int n,m,k,used[maxn],lk[maxn][maxn],mark[maxn];
bool find(int u){
    for(int i = 1;i <= m;i++){
        if(lk[u][i]&&!used[i]){
            used[i] = 1;
            if(mark[i] == 0||find(mark[i])){
                mark[i] = u;
                return true;
            }
        }

    }
    return false;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n)){
        if(n == 0)
            break;
        memset(lk,0,sizeof(lk));
        memset(mark,0,sizeof(mark));
        scanf("%d%d",&m,&k);
        int i,a,b,c;
        for(i = 1;i <= k;i++){
            scanf("%d%d%d",&c,&a,&b);
            lk[a][b] = 1;
        }
        int ans=0;
        for(i = 1;i <= n;i++){
        memset(used,0,sizeof(used));
        if(find(i)) ans++;
        }
        cout<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shimu/p/5799350.html