题意:
小T准备在家里摆放几幅画,为此他买来了N幅画和N个画框。为了体现他的品味,小T希望能合理地搭配画与画框,使得其显得既不过于平庸也不太违和。对于第 幅画与第 个画框的配对,小T都给出了这个配对的平凡度Aij 与违和度Bij 。整个搭配方案的总体不和谐度为每对画与画框平凡度之和与每对画与画框违和度的乘积。具体来说,设搭配方案中第i幅画与第Pi个画框配对,则总体不和谐度为
小T希望知道通过搭配能得到的最小的总体不和谐度是多少。
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#define N 100
using namespace std;
int inf=1<<25,ans,n;
struct point{
int x,y;
friend point operator -(point a,point b) {return (point){a.x-b.x,a.y-b.y};}
friend int operator *(point a,point b) {return a.x*b.y-a.y*b.x;}
};
struct KM{
int a[N][N],lx[N],ly[N],match[N],sla[N],A[N][N],B[N][N];
bool vx[N],vy[N];
point res;
bool dfs(int x)
{
if(vx[x]) return 0;
vx[x]=1;
for(int y=1;y<=n;y++)
{
if(lx[x]+ly[y]==a[x][y])
{
vy[y]=1;
if(match[y]==0 || dfs(match[y])) {match[y]=x;return 1;}
}
else sla[y]=min(sla[y],lx[x]+ly[y]-a[x][y]);
}
return 0;
}
point work()
{
for(int i=1;i<=n;i++) lx[i]=ly[i]=match[i]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
lx[i]=max(lx[i],a[i][j]);
for(int i=1;i<=n;i++)
while(1)
{
for(int j=1;j<=n;j++) vx[j]=vy[j]=0,sla[j]=inf;
if(dfs(i)) break;
int d=inf;
for(int j=1;j<=n;j++) d=min(d,sla[j]);
for(int j=1;j<=n;j++)
{
if(vx[j]) lx[j]-=d;
if(vy[j]) ly[j]+=d;
}
}
res.x=res.y=0;
for(int i=1;i<=n;i++) res.x+=A[match[i]][i],res.y+=B[match[i]][i];
if(res.x*res.y<ans || ans==-1) ans=res.x*res.y;
return res;
}
}hehe;
int A[N][N],B[N][N];
void solve(point a,point b)
{
point c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
hehe.a[i][j]=-(A[i][j]*(a.y-b.y)+B[i][j]*(b.x-a.x));
c=hehe.work();
if((a-b)*(a-c)>=0) return;
solve(a,c);
solve(c,b);
}
int main()
{
int z;scanf("%d",&z);
while(z--)
{
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++)
hehe.A[i][j]=A[i][j],hehe.B[i][j]=B[i][j];
ans=-1;
point a,b;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
hehe.a[i][j]=-A[i][j];
a=hehe.work();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
hehe.a[i][j]=-B[i][j];
b=hehe.work();
solve(a,b);
printf("%d\n",ans);
}
return 0;
}
题解:
模了题解,学了最小乘积树和km这两种(奇怪)的算法。。(小姿势)
这题只不过不是生成树而是带权匹配,把kruscal换成km套最小乘积树的算法就行了。。复杂度不会算,不过km是O(
n3
)的,似乎这个期望就是O(
n4
)的了?