zoukankan      html  css  js  c++  java
  • BZOJ3571 [Hnoi2014]画框 【分治 + KM算法】

    题目链接

    BZOJ3571

    题解

    如果知道最小乘积生成树,那么这种双权值乘积最小就是裸题了
    将两权值和作为坐标,转化为二维坐标系下凸包上的点,然后不断划分分治就好了

    这里求的是最小匹配值,每次找点套一个二分图最小权匹配
    为什么用KM算法?因为这道题丧心病狂卡费用流QAQ

    写完就A啦,十分的感人

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 75,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int n,X[maxn][maxn],Y[maxn][maxn];
    int w[maxn][maxn],expa[maxn],expb[maxn],cp[maxn],visa[maxn],visb[maxn],dl[maxn];
    struct point{int x,y;}ans;
    inline point  operator -(const point& a,const point& b){
    	return (point){a.x - b.x,a.y - b.y};
    }
    inline LL operator *(const point& a,const point& b){
    	return 1ll * a.x * b.y - 1ll * a.y * b.x;
    }
    inline bool operator <(const point& a,const point& b){
    	return 1ll * a.x * a.y == 1ll * b.x * b.y ? a.x < b.x : 1ll * a.x * a.y < 1ll * b.x * b.y;
    }
    bool dfs(int u){
    	visa[u] = true;
    	REP(i,n) if (!visb[i]){
    		int kl = expa[u] + expb[i] - w[u][i];
    		if (!kl){
    			visb[i] = true;
    			if (!cp[i] || dfs(cp[i])) {cp[i] = u; return true;}
    		}
    		else dl[i] = min(dl[i],kl);
    	}
    	return false;
    }
    point km(){
    	REP(i,n) expa[i] = -INF,expb[i] = cp[i] = 0;
    	REP(i,n) REP(j,n) expa[i] = max(expa[i],w[i][j]);
    	REP(i,n){
    		REP(j,n) dl[j] = INF;
    		while (true){
    			REP(j,n) visa[j] = visb[j] = false;
    			if (dfs(i)) break;
    			int kl = INF;
    			REP(j,n) if (!visb[j]) kl = min(kl,dl[j]);
    			REP(j,n){
    				if (visa[j]) expa[j] -= kl;
    				if (visb[j]) expb[j] += kl;
    					else dl[j] -= kl;
    			}
    		}
    	}
    	point re; re.x = re.y = 0;
    	REP(i,n) re.x += X[cp[i]][i],re.y += Y[cp[i]][i];
    	if (re < ans) ans = re;
    	return re;
    }
    void solve(point A,point B){
    	REP(i,n) REP(j,n) w[i][j] = -((A.y - B.y) * X[i][j] + (B.x - A.x) * Y[i][j]);
    	point C = km();
    	if ((C - A) * (B - A) <= 0) return;
    	solve(A,C); solve(C,B);
    }
    int main(){
    	int T = read();
    	while (T--){
    		n = read(); ans.x = INF; ans.y = INF;
    		REP(i,n) REP(j,n) X[i][j] = read();
    		REP(i,n) REP(j,n) Y[i][j] = read();
    		REP(i,n) REP(j,n) w[i][j] = -X[i][j];
    		point A = km();
    		REP(i,n) REP(j,n) w[i][j] = -Y[i][j];
    		point B = km();
    		solve(A,B);
    		printf("%d
    ",ans.x * ans.y);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    记一次Redis+Getshell经验分享
    冰蝎动态二进制加密WebShell基于流量侧检测方案
    ubuntu16下安装mongodb 3.6
    centos安装sass环境必看
    CLR 调试体系结构
    CLR 调试概述
    CLR Exception---E0434352
    关于System.MissingMethodException异常
    关于异常System.ArgumentException
    从.NET/CLR返回的hresult:0x8013XXXX的解释
  • 原文地址:https://www.cnblogs.com/Mychael/p/8995121.html
Copyright © 2011-2022 走看看