bzoj3571: [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
3
4 3 2
2 3 4
3 2 1
2 3 2
2 2 4
1 1 3
Sample Output
HINT
第1幅画搭配第3个画框,第2幅画搭配第1个画框,第3 幅画搭配第2个画框,则总体不和谐度为30
N<=70,T<=3,Aij<=200,Bij<=200
题解:
将某个方案的ΣA看成横坐标,ΣB看成纵坐标
把所有的方案看成一个点集,显然只有这个点集靠近坐标轴的点形成的下凸壳才有可能是答案
首先,显然x最小的点和y最小的点都在这个下凸壳上
分别将A,B数组取反去作KM即可知道这两个点
我们画个图容易知道,假如有两个点a,b在凸壳上,那么在ab这条直线下方离这条直线最远的点也会在凸壳上
然后就可以分治了
如何求这个最远的点
假设a,b都在凸壳上,c是最远的点,显然三角形abc的面积会是最大的
所以2*S=向量(ac)和向量(ab)的叉积
=(c.x-a.x,c.y-a.y)*(b.x-a.x,b.y-a.y)
=(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*(a.y-b.y)+a.y*(b.x-a.x)
后面两项是常数,所以我们要最大化c.x*(b.y-a.y)+c.y*(a.x-b.x)
这里我们只需要将KM中的权值数组g[i][j]=(b.y-a.y)*a[i][j]+(a.x-b.x)*b[i][j],然后KM之后就能求出c点了
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 75 7 #define inf 1061109567 8 using namespace std; 9 char ch; 10 bool ok; 11 void read(int &x){ 12 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 13 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 14 if (ok) x=-x; 15 } 16 struct Point{int x,y;}st,ed; 17 bool operator==(Point a,Point b){return a.x==b.x&&a.y==b.y;} 18 int T,n,a[maxn][maxn],b[maxn][maxn]; 19 int g[maxn][maxn],lx[maxn],ly[maxn],sla[maxn],match[maxn]; 20 bool vx[maxn],vy[maxn]; 21 bool dfs(int u){ 22 vx[u]=true; 23 for (int v=1;v<=n;v++) 24 if (!vy[v]){ 25 int t=lx[u]+ly[v]-g[u][v]; 26 if (!t){ 27 vy[v]=true; 28 if (!match[v]||dfs(match[v])){match[v]=u;return true;} 29 } 30 else sla[v]=min(sla[v],t); 31 } 32 return false; 33 } 34 Point km(){ 35 memset(lx,0,sizeof(lx)); 36 memset(ly,0,sizeof(ly)); 37 memset(match,0,sizeof(match)); 38 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) lx[i]=max(lx[i],g[i][j]); 39 for (int x=1;x<=n;x++){ 40 memset(sla,63,sizeof(sla)); 41 for (;;){ 42 memset(vx,0,sizeof(vx)); 43 memset(vy,0,sizeof(vy)); 44 if (dfs(x)) break; 45 int d=inf; 46 for (int i=1;i<=n;i++) if (!vy[i]) d=min(d,sla[i]); 47 for (int i=1;i<=n;i++) if (vx[i]) lx[i]-=d; 48 for (int i=1;i<=n;i++) vy[i]?ly[i]+=d:sla[i]-=d; 49 } 50 } 51 Point ans=(Point){0,0}; 52 for (int i=1;i<=n;i++) ans.x+=a[match[i]][i],ans.y+=b[match[i]][i]; 53 return ans; 54 } 55 int solve(Point st,Point ed){ 56 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=(ed.y-st.y)*a[i][j]+(st.x-ed.x)*b[i][j]; 57 Point mid=km(); 58 if (st==mid||ed==mid) return min(st.x*st.y,ed.x*ed.y); 59 return min(solve(st,mid),solve(mid,ed)); 60 } 61 int main(){ 62 for (read(T);T;T--){ 63 read(n); 64 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) read(a[i][j]); 65 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) read(b[i][j]); 66 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=-a[i][j]; 67 st=km(); 68 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=-b[i][j]; 69 ed=km(); 70 printf("%d\n",solve(st,ed)); 71 } 72 return 0; 73 }