匈牙利算法模板+KM算法模板

匈牙利算法模板   时间复杂度为O(VE)   V为二分图左边的顶点数,E为二分图中边的数目

#include<stdio.h>
#include<string.h>
const int maxn=1010;
const int maxm=20010;
const int MAX=10001;
const int INF=1000000000;
int line[maxn];
int n,m,cnt,slack;
int head[maxn];
bool used[maxn];//Y集合中点的状态
struct EDGE
{
	int u,v,w,next;
}edge[maxm];
void addedge(int u,int v,int w)
{
	edge[cnt].u=u;edge[cnt].v=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt++;
}
bool find(int u)//寻找增广路
{
	for(int e=head[u];e!=-1;e=edge[e].next){//对于所有u->v
		int v=edge[e].v;
		if(!used[v])//v没有被标记
		{
			used[v]=true;
			if(line[v]==-1||find(line[v])){//v没有匹配或者v有增广路
				line[v]=u;
				return 1;
			}
		}
	}
	return 0;
}
int Hungary()//返回匹配数
{
	int all=0;
	for (int i=1;i<=n;i++)  
    {  
        memset(used,0,sizeof(used));   
        if(find(i)) all+=1;  
    }  
	return all;
}

KM算法模板

#include<stdio.h>
#include<string.h>
const int maxn=1010;
const int maxm=20010;
const int MAX=10001;
const int INF=1000000000;
int lx[maxn],ly[maxn];//顶标
bool visx[maxn],visy[maxn];//开两个数组是需要记录X集合和Y集合在相等子图中的状态。
int line[maxn];//line[i]为Y集合中i与X集合中的line[i]配对
int we[maxn];//已配对所对应的边权值
int n,m,cnt,slack;
int head[maxn];
struct EDGE
{
	int u,v,w,next;
}edge[maxm];
bool find(int u)
{
	visx[u]=true;
	for(int e=head[u];e!=-1;e=edge[e].next){
		int v=edge[e].v;
		if(!visy[v])
		{
			int t=lx[u]+ly[v]-edge[e].w;
			if(t==0)
			{
				visy[v]=true;
				if(line[v]==-1||find(line[v])){
					line[v]=u;
					we[v]=edge[e].w;//记录权值
					return 1;
				}
			}
			else if(t<slack){
				slack=t;
			}
		}
	}
	return 0;
}
bool KM()
{
	memset(ly,0,sizeof(ly));
	memset(lx,0,sizeof(lx));
	memset(line,-1,sizeof(line));
	for(int u=1;u<=n;u++)
	{
		for(int e=head[u];e!=-1;e=edge[e].next)
		{
			if(edge[e].w>lx[u])
				lx[u]=edge[e].w;
		}
	}
	for(int u=1;u<=n;u++)
	{
		while(true)
		{
			slack=INF;
			memset(visx,0,sizeof(visx));
			memset(visy,0,sizeof(visy));
			if(find(u))break;
			if(slack==INF)return 0;
			for(int i=1;i<=n;i++)
			{
				if(visx[i])lx[i]-=slack;
				if(visy[i])ly[i]+=slack;
			}
		}
	}
	return 1;
}
void addedge(int u,int v,int w)
{
	edge[cnt].u=u;edge[cnt].v=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt++;
}
struct KM{
    double lx[N],ly[N];//顶标
    bool visx[N],visy[N];
    int line[N];
    double we[N];//已配对所对应边权值
    int nx,ny;
    double slack;
    bool find(int u){
        visx[u]=true;
        for(int v=1;v<=ny;v++){
            if(!visy[v])//v不在相等子图中
            {
                double t=lx[u]+ly[v]-G[u][v];
                if(fabs(t)<eps){
                    visy[v]=1;
                    if(line[v]==-1||find(line[v])){
                        line[v]=u;
                        ans[u]=v;
                        we[v]=G[u][v];
                        return 1;
                    }
                }
            }
        }
        return 0;
    }
    bool km(){//返回是否完备匹配
        for(int i=1;i<=nx;i++){
            lx[i]=-INF;ly[i]=0;
            line[i]=-1;
            for(int j=1;j<=ny;j++){
                if(G[i][j]-lx[i]>eps)
                    lx[i]=G[i][j];//初始化为xi所连接的最大权值
            }
        }
        for(int u=1;u<=nx;u++)
        {
            while(true){
                clr(visx);clr(visy);
                if(find(u))break;
                for(int i=1;i<=nx;i++){
                    if(visx[i])lx[i]-=slack;
                }
                for(int i=1;i<=ny;i++){
                    if(visy[i])ly[i]+=slack;
                }
                slack=INF;
                for(int i=1;i<=nx;i++){
                    if(visx[i]){
                        for(int j=1;j<=ny;j++){
                            if(!visy[j]){
                                slack=min(slack,lx[i]+ly[j]-G[i][j]);
                            }
                        }
                    }
                }
                if(slack==INF)break;
            }
        }
        return 1;
    }
    int best_match(){
        double res=0;
        km();
        for(int u=1;u<=ny;u++){
            if(line[u]==-1)continue;
            res+=we[u];
        }
        return res;
    }
}kk;




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值