zoukankan      html  css  js  c++  java
  • 分配问题(二部图的最佳匹配 KM) 线性规划与网络流24题

    //http://www.cnblogs.com/IMGavin/
    #include <iostream>
    #include <stdio.h>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <map>
    #include <stack>
    #include <set>
    #include <bitset>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    #define gets(A) fgets(A, 1e8, stdin)
    const int INF = 0x3F3F3F3F, N = 108, MOD = 1003;
    
    const double EPS = 1e-6;
    int val[N][N];
    bool visx[N], visy[N];
    //始终有lx[x] + ly[y] >= w[x][y],且结束后顶标之和最小
    int lx[N], ly[N], slack[N], match[N];//match[y]表示Y集节点y对X的匹配
    int nx, ny;//X集Y集节点个数,要先初始化
    
    bool Hungary(int u){
    	visx[u] = true;
    	for(int i = 0; i < ny; i++){
    		if(!visy[i]){
                if(lx[u] + ly[i] == val[u][i]){
                    visy[i] = true;
                    if(match[i] == -1 || Hungary(match[i])){
                        match[i] = u;
                        return true;
                    }
    
                }else{
                    slack[i] = min(slack[i], lx[u] + ly[i] - val[u][i]);
                }
    		}
    	}
    	return false;
    }
    
    void KM(){
        memset(match, -1, sizeof(match));
    	memset(lx, 0, sizeof(lx)); //初始化顶标
    	memset(ly, 0, sizeof(ly)); //ly[i]为0
    	 //lx[i]为权值最大的边
    	for(int i = 0; i < nx; i++){
    		for(int j = 0; j < ny; j++){
                lx[i] = max(lx[i], val[i][j]);
    		}
    	}
    	for(int i = 0; i < nx; i++){
    		for(int j = 0; j < ny; j++){
                slack[j] = INF;
    		}
    		while(1){
    			memset(visx, 0, sizeof(visx));
    			memset(visy, 0, sizeof(visy));
    			if(Hungary(i)){
                    break;
                }else{
    				int tp = INF;
    				for(int j = 0; j < ny; j++){
                        if(!visy[j] && tp > slack[j]){
                            tp = slack[j];
                        }
                    }
    				for(int j = 0; j < nx; j++){
    					if(visx[j]){
                            lx[j] -= tp;
    					}
    				}
    
    				for(int j = 0; j < ny; j++){
    					if(visy[j]){
                            ly[j] += tp;
    					}else{
                            slack[j] -= tp;
    					}
    				}
    			}
    		}
    	}
    }
    
    int main(){
    	int n;
    	while(cin >> n){
    		nx = ny = n;
    		for(int i = 0; i < n; i++){
    			for(int j = 0; j < n; j++){
    				scanf("%d", &val[i][j]);
    				val[i][j] = -val[i][j];
    			}
    		}
    		KM();
    		int ans = 0;
    		for(int i = 0; i < n; i++){
    			ans += val[match[i]][i];
    		}
    
    		cout<<-ans<<endl;
    
    		for(int i = 0; i < n; i++){
    			for(int j = 0; j < n; j++){
    				val[i][j] = -val[i][j];
    			}
    		}
    		KM();
    		ans = 0;
    		for(int i = 0; i < n; i++){
    			ans += val[match[i]][i];
    		}
    
    		cout<<ans<<endl;
    	}
    	
    
    	return 0;
    }
    

      

  • 相关阅读:
    angular入门学习文档之一
    将SDL程序变成网页(使用emscripten)
    Nim使用OpenGL
    C++移动操作,RVO和NRVO
    从零开始制作一个粒子系统
    cocos2d-x学习之路(一)——安装cocos2d-x
    堆排序
    开发zeroc ice应用入门(java开发ice应用,python开发ice应用,java与python结合开发ice服务)
    eclipse自动提示设置以及问题:去除变量自动提示(图文详解)
    ubuntu安装新版QQ
  • 原文地址:https://www.cnblogs.com/IMGavin/p/6388134.html
Copyright © 2011-2022 走看看