zoukankan      html  css  js  c++  java
  • bzoj 3571: [Hnoi2014]画框

    Description

    小T准备在家里摆放几幅画,为此他买来了N幅画和N个画框。为了体现他的品味,小T希望能合理地搭配画与画框,使得其显得既不过于平庸也不太违和。对于第 幅画与第 个画框的配对,小T都给出了这个配对的平凡度Aij 与违和度Bij 。整个搭配方案的总体不和谐度为每对画与画框平凡度之和与每对画与画框违和度的乘积。具体来说,设搭配方案中第i幅画与第Pi个画框配对,则总体不和谐度为

    小T希望知道通过搭配能得到的最小的总体不和谐度是多少。

    Input

    输入文件第 行是一个正整数T ,表示数据组数,接下来是T组数据。
    对于每组数据,第 行是一个正整数N,表示有N对画和画框。
    第2到第N+1行,每行有N个非负整数,第i+1 行第j个数表示Aij 。
    第N+2到第2*N+1行,每行有N个非负整数,第i+N+1 行第j个数表示Bij 。

    Output

    包含T行,每行一个整数,表示最小的总体不和谐度

    Sample Input

    1
    3
    4 3 2
    2 3 4
    3 2 1
    2 3 2
    2 2 4
    1 1 3

    Sample Output

    30

    HINT

    第1幅画搭配第3个画框,第2幅画搭配第1个画框,第3 幅画搭配第2个画框,则总体不和谐度为30

    N<=70,T<=3,Aij<=200,Bij<=200

    Source

    如果知道最小乘积生成树的话,那这题就是真的裸得不能再裸了;

    具体操作是这样的,把一个最大匹配的∑ai看成横坐标,∑bi看成纵坐标,那么就是就对应着平面上的点(x,y),答案就是x*y;

    我们发现答案一定在下凸壳上,然后我们考虑如何求解,与二维乘积最小生成树是一样的;

    这里发一个最小乘积生成树的链接,说得特别好,主要是有图:http://www.cnblogs.com/autsky-jadek/p/3959446.html

    具体思想就是确定一条直线,然后在左下方找一个距离最远的点,找这个点就是找三角形面积最大的点,这个就是把叉积的式子展开,然后用费用流找到那个点,

    然后往下递归,直到左下角没有点,这个用叉积面积<=0判;

    //MADE BY QT666
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=20050;
    const int Inf=2147483647;
    struct Point{
        int x,y;
    };
    int a[100][100],b[100][100],S,T,n,ans,tmp,cnt;
    struct data{
        int head[N],to[N],nxt[N],s[N],cc[N],in[N],fa[N],vx[N],vy[N],q[N*10],dis[N],cost;
        void Addedge(int x,int y,int z,int u,int X,int Y) {
    	to[++cnt]=y,s[cnt]=z,cc[cnt]=u,nxt[cnt]=head[x],head[x]=cnt,vx[cnt]=X,vy[cnt]=Y;
        }
        void lnk(int x,int y,int z,int u,int X,int Y) {
    	Addedge(x,y,z,u,X,Y),Addedge(y,x,0,-u,-X,-Y);
        }
        bool spfa(Point &a) {
    	for(int i=S; i<=T; i++) dis[i]=Inf,in[i]=0;
            int t=0,sum=1;
    	q[0]=S,in[S]=1,dis[S]=0;
    	while(t<sum) {
    	    int x=q[t++];in[x]=0;
    	    for(int i=head[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(s[i]&&dis[y]>dis[x]+cc[i]) {
    		    dis[y]=dis[x]+cc[i];fa[y]=i;
    		    if(!in[y]) in[y]=1,q[sum++]=y;
    		}
    	    }
    	}
    	if(dis[T]==Inf) return 0;
    	for(int i=fa[T];i;i=fa[to[i^1]]){
    	    a.x+=vx[i];a.y+=vy[i];
    	    s[i]--,s[i^1]++;
    	}
    	cost+=dis[T];
    	return 1;
        }
        Point Mincost() {Point c=(Point){0,0};while(spfa(c));return c;;}
        void build(int X,int Y){
    	memset(head,0,sizeof(head));cnt=1;
    	for(int i=1;i<=n;i++){
    	    for(int j=1;j<=n;j++){
    		lnk(i,j+n,1,X*a[i][j]+Y*b[i][j],a[i][j],b[i][j]);
    	    }
    	    lnk(S,i,1,0,0,0);lnk(i+n,T,1,0,0,0);
    	}
        }
    }Gragh;
    int Cross(Point a,Point b,Point c){
        return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
    }
    void solve(Point a,Point b){
        Gragh.build(a.y-b.y,b.x-a.x);Point C=Gragh.Mincost();
        ans=min(ans,C.x*C.y);
        if(Cross(b,a,C)<=0) return;
        solve(a,C);solve(C,b);
    }
    int main(){
        freopen("frame.in","r",stdin);
        freopen("frame.out","w",stdout);
        int t;scanf("%d",&t);
        while(t--){
    	scanf("%d",&n);S=0,T=2*n+1;
    	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]);
    	}
    	Gragh.build(1,0);
    	Point A=Gragh.Mincost();
    	Gragh.build(0,1);
    	Point B=Gragh.Mincost();
    	ans=Inf;ans=min(ans,min(A.x*A.y,B.x*B.y));
    	solve(A,B);printf("%d
    ",ans);
        }
        return 0;
    }
    
     
  • 相关阅读:
    Win10 WSL Ubuntu18.04 编译安装MySQL5.7
    PHP7 深入理解
    php session 测试
    nginx 匹配路由分发php和golang
    composer 库无法提交git
    Win10 1803安装Ubuntu1804子系统
    dhtmlxTreeGrid使用
    win7 64位系统下安装PL/SQL连接Oracle服务器的解决方法
    转载--eclipse快捷键
    JUnit4学习笔记2-Eclipse中使用JUint4进行单元测试
  • 原文地址:https://www.cnblogs.com/qt666/p/7650417.html
Copyright © 2011-2022 走看看