• 【LOJ】#2205. 「HNOI2014」画框


    题解

    我原来根本不会KM

    更新每个节点增加的最小值的时候,要忽略那个方访问过的右节点!!!

    然后就和最小乘积生成树一样了

    代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <cmath>
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define eps 1e-7
    #define MAXN 100005
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef double db;
    typedef vector<int> poly;
    
    template<class T>
    void read(T &res) {
    	res = 0;char c = getchar();T f = 1;
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		res = res * 10 + c - '0';
    		c = getchar();
    	}
    	res *= f;
    }
    template<class T>
    void out(T x) {
    	if(x < 0) {putchar('-');x = -x;}
    	if(x >= 10) {
    		out(x / 10);
    	}
    	putchar('0' + x % 10);
    }
    int T;
    int N,ans;
    int A[75][75],B[75][75],C[75][75];
    bool vis_l[75],vis_r[75];
    int slack[75],matk[75],ex_l[75],ex_r[75];
    bool match(int u) {
    	vis_l[u] = 1;
    	for(int v = 1 ; v <= N ; ++v) {
    		if(vis_r[v]) continue;
    		int gap = C[u][v] - (ex_l[u] + ex_r[v]);
    		if(gap == 0) {
    			vis_r[v] = 1;
    			if(matk[v] == -1 || match(matk[v])) {
    				matk[v] = u;
    				return 1;
    			}
    		}
    		else slack[v] = min(slack[v],gap);
    	}
    	return 0;
    }
    pii KM() {
    	for(int i = 1 ; i <= N ; ++i) matk[i] = -1;
    	for(int i = 1 ; i <= N ; ++i) {
    		ex_l[i] = 1000000000;ex_r[i] = 0;
    		for(int j = 1 ; j <= N ; ++j) {
    			if(C[i][j] < ex_l[i]) ex_l[i] = C[i][j];
    		}
    	}
    	for(int i = 1 ; i <= N ; ++i) {
    		for(int j = 1 ; j <= N ; ++j) slack[j] = 1000000000;
    		while(1) {
    			memset(vis_l,0,sizeof(vis_l));
    			memset(vis_r,0,sizeof(vis_r));
    			if(match(i)) break;
    			int d = 1000000000;
    			for(int j = 1 ; j <= N ; ++j) if(!vis_r[j]) d = min(d,slack[j]);
    			for(int j = 1 ; j <= N ; ++j) {
    				if(vis_l[j]) ex_l[j] += d;
    				if(vis_r[j]) ex_r[j] -= d;
    				else slack[j] -= d;
    			} 
    		}
    	}
    	int rA = 0,rB = 0;
    	for(int i = 1 ; i <= N  ; ++i) {
    		rA += A[matk[i]][i];
    		rB += B[matk[i]][i];
    	}
    	return mp(rA,rB);
    }
    void Init() {
    	read(N);
    	for(int i = 1 ; i <= N ; ++i) {
    		for(int j = 1 ; j <= N ; ++j) {
    			read(A[i][j]);
    		}
    	}
    	for(int i = 1 ; i <= N ; ++i) {
    		for(int j = 1 ; j <= N ; ++j) {
    			read(B[i][j]);
    		}
    	}
    }
    void Calc(pii S,pii T) {
    	for(int i = 1 ; i <= N ; ++i) {
    		for(int j = 1 ; j <= N ; ++j) {
    			C[i][j] = (S.se - T.se) * A[i][j] + (T.fi - S.fi) * B[i][j];
    		}
    	}
    	pii M = KM();
    	ans = min(ans,M.fi * M.se);
    	if((T.fi - M.fi) * (S.se - M.se) - (S.fi - M.fi) * (T.se - M.se) <= 0) return;
    	Calc(S,M);Calc(M,T);
    }
    void Solve() {
    	ans = 0x7fffffff;
    	memcpy(C,A,sizeof(C));
    	pii S = KM();
    	ans = min(ans,S.fi * S.se);
    	memcpy(C,B,sizeof(C));
    	pii T = KM();
    	ans = min(ans,T.fi * T.se);
    	if(S != T) Calc(S,T);
    	out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
    	freopen("f1.in","r",stdin);
    #endif
    	read(T);
    	while(T--) {
    		Init();
    		Solve();
    	}
    	return 0;
    }
    
  • 相关阅读:
    windows 7中添加新硬件的两种方法(本地回环网卡)
    文档编辑大神
    BIOS Setup
    Sound Card Chip
    modem&NIC&sound card
    Monitor
    chassis & power
    HDD
    C#开发实例 鼠标篇
    编程之美 1.8小飞的电梯调度算法
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9220692.html
Copyright © 2020-2023  润新知