hdu 2255 奔小康赚大钱 KM算法 模板题

这是复杂度为O(n^4)
#include 
#include 
#include 
using namespace std ;

const int N = 300 + 11 ;

struct Graph {
    int from[N] ;//记录匹配状态
    int w[N][N] ;//边权
    int lx[N] ,ly[N] ;//点标
    bool sx[N] , sy[N] ;
    int nx , ny ;//nx左节点的个数,ny右节点的个数

    bool match(int u) {
        sx[u] = true ;
        for(int i = 1; i <= ny ; ++i) {
            if(!sy[i] && lx[u] + ly[i] == w[u][i]) {
                sy[i] = true ;
                if(from[i] ==  -1 || match(from[i])) {//无数次写成match(i),,,,注意了
                    from[i] = u ;
                    return true ;
                }
            }
        }
        return false ;
    }

    void std_fun() {
        memset(lx , 0 , sizeof(lx)) ;
        memset(ly , 0 , sizeof(ly)) ;
        for(int i = 1; i <= nx ;++i) {
            for(int j= 1; j <= ny; ++j) {
                scanf("%d",&w[i][j]);
                lx[i] = max(lx[i] , w[i][j]) ;
            }
        }
        memset(from , -1 , sizeof(from)) ;
        for(int k = 1; k <= nx; ++k) {
            while(true) {
                memset(sx , 0 , sizeof(sx)) ;
                memset(sy , 0 , sizeof(sy)) ;
                if(match(k)) break ;
                int d = (1<<30)-1+(1<<30) ;
                for(int i = 1 ; i <= nx ; ++i) {
                    if(sx[i]) {
                        for(int j = 1; j <= ny ; ++j) {
                            if(!sy[j]) {//这里是非,,,,
                                d = min(d , lx[i] + ly[j] - w[i][j]) ;
                            }
                        }
                    }
                }
                for(int i = 1; i <= nx; ++i) {
                    if(sx[i]) lx[i] -= d ;
                }
                for(int i = 1; i <= ny ; ++i){
                    if(sy[i]) ly[i] += d ;
                }
            }
        }
        int sum = 0 ;
        for(int i = 1; i <= ny ; ++i) {
            if(from[i] != -1) sum += w[from[i]][i] ;
        }
        printf("%d\n",sum) ;
    }
}g ;

int main() {
    int n;
    while(scanf("%d",&n)==1) {
        g.nx = g.ny = n ;
        g.std_fun() ;
    }
}

复杂度为O(n^3) :但比上面的只快了100多ms

#include 
#include 
#include 
using namespace std ;

const int N = 300 + 11 ;

struct Graph {
	int w[N][N] ;
	int lx[N] , ly[N] ;
	int from[N] , slack[N] ;//右节点匹配状态,,记录点的权值差
	bool sx[N] , sy[N] ;
	int nx , ny ;//左右节点数

	void std_fun() {
		memset(lx , 0 , sizeof(lx)) ;
		memset(ly , 0 , sizeof(ly)) ;
		for(int i = 1; i <= nx ;++i) {
			for(int j = 1; j <= ny ;++j) {
				scanf("%d",&w[i][j]) ;
				if(w[i][j] > lx[i]) lx[i] = w[i][j] ;
			}
		}
		memset(from , -1 ,sizeof(from)) ;
		for(int i = 1; i <= nx ; ++i) {
            memset(slack , (1<<6) , sizeof(slack)) ;
			while(true) {
				memset(sx , 0 , sizeof(sx)) ;
				memset(sy , 0 , sizeof(sy)) ;
				if(match(i)) break ;
				int d = (1<<30) ;
				for(int i = 1; i <= ny ; ++i) {
					if(!sy[i] && slack[i] < d) d = slack[i] ;
				}
				for(int i = 1; i <= nx ; ++i) {
					if(sx[i]) lx[i] -= d ;
				}
				for(int i = 1; i <= ny ; ++i) {
					if(sy[i]) ly[i] += d ;
					//else slack[i] -= d ;//这句应该可以不要,但大神的模板这里有,,,
				}
			}
		}
		int sum = 0 ;
		for(int i = 1; i <= ny ; ++i) {
			if(from[i] != -1) sum += w[from[i]][i] ;
		}
		printf("%d\n" , sum) ;
	}

	bool match(int u) {
		sx[u] = true ;
		for(int i = 1; i <= ny ; ++i) {
            if(sy[i]) continue ;
			int tmp = lx[u] + ly[i] - w[u][i] ;
			if(tmp == 0) {
				sy[i] = true ;
				if(from[i] == -1 || match(from[i])) {
					from[i] = u ;
					return true ;
				}
			}else {
				if(slack[i] > tmp) slack[i] = tmp ;
			}
		}
		return false ;
	}
}g ;

int main() {
	int n ;
	while(scanf("%d",&n)==1) {
		g.nx = g.ny = n ;
		g.std_fun() ;
	}
}



你可能感兴趣的:(二分图)