zoukankan      html  css  js  c++  java
  • KM算法

     用途:求出带权二分图的最大权匹配

      流程:

    1. 把左边每个点的顶标设为与它相连的边中最大的权值,右边每个点顶标设为(0)
    2. 对于每个点(i),进行步骤(3)
    3. 在与(i)相连的所有边中找到一条边((i,u))使得(w(i,u)=val(i)+val(u)),如果(u)未匹配则匹配(i)(u),进入步骤(4);如果(u)已匹配则对(u)重复步骤(3)。都找完后进入步骤(4)
    4. 若找到了满足条件的点(u),则匹配(i)(u),重复步骤(2)。若没有找到,进入步骤(5)
    5. 把上次的(3)操作中涉及的所有左边点顶标(-1),右边点顶标(+1),重复步骤(3)
    可以记录最少的顶标差d,将其优化至(n^3)

     举个例子:

     懒得举了

    代码如下

    此为n^4代码

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,e;
    int array[1001][1001];//邻接存图
    int match[1001];//匹配
    int value_left[1001];//左点顶标
    int value_right[1001];//右点顶标
    int visit_left[1001];//左点标记
    int visit_right[1001];//右点标记
    int ans;
    inline int read(){//快读
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    int augment(int x){//增广操作(步骤3)
    	visit_left[x]=1;//给涉及的点打标记
    	for(int i=1;i<=m;i++){//遍历每一条边
    		if(!visit_right[i]&&value_right[i]+value_left[x]==array[x][i]){//如果i此次未被涉及过且满足条件
    			visit_right[i]=1;//涉及i
    			if(match[i]==-1||augment(match[i])){//如果i未被匹配
    				match[i]=x;//把i与x匹配
    				return 1;//返回成功
    			}
    		}
    	}
    	return 0;//如果一个都不行,返回失败
    }
    int main(){
    	memset(match,-1,sizeof match);
    	n=read();
    	m=read();
    	e=read();
    	for(int i=1;i<=e;i++){
    		int u,v,w;
    		u=read();
    		v=read();
    		w=read();
    		array[u][v]=w;
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){//处理左点顶标
    			value_left[i]=max(value_left[i],array[i][j]);
    		}
    	}
    	for(int i=1;i<=n;i++){//每次记得清空标记
    		memset(visit_left,0,sizeof visit_left);
    		memset(visit_right,0,sizeof visit_right);
    		while(!augment(i)){//对于一个点如果增广不成功就不停重复
    			for(int j=1;j<=n;j++){//如果左点被访问则-1
    				value_left[j]-=visit_left[j];
    			}
    			for(int j=1;j<=m;j++){//如果右点被访问则+1
    				value_right[j]+=visit_right[j];
    			}
    			memset(visit_left,0,sizeof visit_left);
    			memset(visit_right,0,sizeof visit_right);
    		}
    	}
    	for(int i=1;i<=m;i++){//统计匹配的答案
    		if(match[i]!=-1)ans+=array[match[i]][i];
    	}
    	cout<<ans;
    	return 0;
    }
    
    
  • 相关阅读:
    测试开发之利器论战
    测试开发的战略战术
    Python日志Logging
    Android自动测试中的monkey工具使用方法
    ADB命令讲解
    学习要深入
    测试开发发展感触
    Web Service测试工具小汇
    python接口测试浅谈
    手机上app测试总结(转)
  • 原文地址:https://www.cnblogs.com/xiong-6/p/11391575.html
Copyright © 2011-2022 走看看