zoukankan      html  css  js  c++  java
  • 【bzoj3751】 Hnoi2014—画框

    http://www.lydsy.com/JudgeOnline/problem.php?id=3571 (题目链接)

    题意

      给出一个$2*N$个点的二分图,$N*N$条边,连接$i$和$j$的边有两个权值$A[i][j]$和$B[i][j]$。求$A$的和与$B$的和之积最小是多少。

    Solution

      很经典的一个模型,右转题解→_→:http://blog.csdn.net/thy_asdf/article/details/50382556

      对于一类乘积最小的题目的方法,我们都可以把每种方案的$x$之和与$y$之和作为它们的坐标$(x,y)$

      要让乘积最小,那么作为答案的点一定在下凸壳上

      我们先求出$x$最小的方案的坐标,再求出$y$最小的方案的坐标

      这就是凸壳的两个端点$A$和$B$

      然后考虑分治,每次找出离直线$AB$最远的点$C$,再继续递归处理

      要使距离最远,那么就是使向量$AB$与$AC$的叉积最大

      即最大化:$(c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x)$

      即:$c.x*(b.y-a.y)+c.y*(a.x-b.x)-a.x*(b.y-a.y)+a.y*(b.x-a.x)$

      后面一部分是常数不用管,我们只要使$c.x*(b.y-a.y)+c.y*(a.x-b.x)$最大化

      那么把$A[i][j]*(b.y-a.y)+B[i][j]*(a.x-b.x)$做$i$匹配$j$的边权

      跑一遍KM求出最大匹配即可得出叉积最大的匹配

      对于其他的最小乘积XXX,就类似地每次跑一遍XXX的算法求出离$AB$最远的方案即可

      直到不可以继续细分下去就返回两端点的匹配较小的一个即可

      虽然可以通过把所有方案构造在凸壳上卡掉这个算法,但随机情况下还是很快的

      

      然而我还不会KM,还学习了一发KM。

      对于边$(x,y)$

      1.$x$,$y$都在当前匹配$lx[x]-=d$,$ly[y]+=d$和不变,原来在新图中,现在还在新图中;

      2.$x$在,$y$不在,$lx[x]-=d$,$ly[y]$不变,原来不在新图中,现在和减小了,可能出现在新图中;

      3.$x$不在,$y$在,$lx[x]$不变,$ly[y]+=d$,原来不在新图中,现在和变大了,不会进入新图中;

      4.$x$,$y$都不在,那么$lx[x]$,$ly[y]$都不变,原来不在新图中,现在也不在新图中。

      所以只有情况$2$会产生新边,不会有边消失,那么新图的边数会越来越大,直到找到一个完备匹配。

    细节

      听说这题卡常。。

      这样是$O(n^4)$的,所以有一个优化,记录一个$slack$数组$slack[y]=min(lx[x]+ly[y]-g[x][y])$($x$与$y$有边)。每次求$d$就只要对不在匹配中的$y$的$slack$取$min$即可

    代码

    // bzoj3571
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf (1ll<<30)
    #define MOD 1000000007
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100;
    int vx[maxn],vy[maxn],lx[maxn],ly[maxn],p[maxn],sla[maxn];
    int n,g[maxn][maxn],A[maxn][maxn],B[maxn][maxn];
    
    struct point {int x,y;
    	friend bool operator == (point a,point b) {
    		return a.x==b.x && a.y==b.y;
    	}
    }L,R;
    
    int match(int x) {
    	vx[x]=1;
    	for (int y=1;y<=n;y++) if (!vy[y]) {
    			int t=lx[x]+ly[y]-g[x][y];
    			if (!t) {
    				vy[y]=1;
    				if (!p[y] || match(p[y])) {p[y]=x;return 1;}
    			}
    			else sla[y]=min(sla[y],t);
    		}
    	return 0;
    }
    point KM() {
    	memset(lx,0,sizeof(lx));
    	memset(ly,0,sizeof(ly));
    	memset(p,0,sizeof(p));
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++) lx[i]=max(lx[i],g[i][j]);
    	for (int x=1;x<=n;x++) {
    		memset(sla,0x7f,sizeof(sla));
    		while (1) {
    			memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));
    			if (match(x)) break;
    			int d=inf;
    			for (int i=1;i<=n;i++) if (!vy[i]) d=min(d,sla[i]);
    			for (int i=1;i<=n;i++) {
    				if (vx[i]) lx[i]-=d;
    				if (vy[i]) ly[i]+=d;
    			}
    		}
    	}
    	point ans=(point){0,0};
    	for (int i=1;i<=n;i++) ans.x+=A[p[i]][i],ans.y+=B[p[i]][i];
    	return ans;
    }
    int solve(point l,point r) {
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++) g[i][j]=A[i][j]*(r.y-l.y)+B[i][j]*(l.x-r.x);
    	point mid=KM();
    	if (l==mid || r==mid) return min(l.x*l.y,r.x*r.y);
    	return min(solve(l,mid),solve(mid,r));
    }
    int main() {
    	int T;scanf("%d",&T);
    	while (T--) {
    		scanf("%d",&n);
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++) scanf("%d",&A[i][j]);
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++) scanf("%d",&B[i][j]);
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++) g[i][j]=-A[i][j];
    		L=KM();
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++) g[i][j]=-B[i][j];
    		R=KM();
    		printf("%d
    ",solve(L,R));
    	}
    	return 0;
    }
    
  • 相关阅读:
    pythonon ddt数据驱动二(json, yaml 驱动)
    selenium 使用隐藏模式打开浏览器
    Selenium -Java (WebDriver)总结(一)---启动浏览器、设置profile&加载插件
    python自动化测试 excle数据驱动
    Selenium+Maven+Jenkins+testNg自动生成测试报告
    【转】java编程思想第20章的注解例子用到的com.sun.mirror的jar包
    [转]java注解与APT技术
    【转】Android官方架构项目之MVP + Clean
    [转]彻底明确怎样设置minSdkVersion和targetSdkVersion
    [转]Android专家级别的面试总结
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6433358.html
Copyright © 2011-2022 走看看