列表

详情


NC20109. [HNOI2014]画框

描述

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

输入描述

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

输出描述

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

示例1

输入:

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

输出:

30

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 217ms, 内存消耗: 464K, 提交时间: 2021-11-16 16:57:15

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
 
struct node{
	int x,y;
	bool operator ==(const node q)const{
		return x==q.x && y==q.y;
	}
};
int T,n;
int a[75][75],b[75][75];
int g[75][75];
int tx[75],ty[75];
bool visx[75],visy[75];
int prep[75];
 
bool find(int x){
	visx[x]=true;
	for(int i=1;i<=n;i++)
		if(!visy[i] && tx[x]+ty[i]==g[x][i]){
			visy[i]=true;
			if(prep[i]==0 || find(prep[i])){
				prep[i]=x;
				return true;
			}
		}
	return false;
}
 
node KM(){
	memset(tx,0,sizeof(tx));
	memset(ty,0,sizeof(ty));
	memset(prep,0,sizeof(prep));
	int mmin=1e9;
	for(int i=1;i<=n;i++){
		while(1){
			memset(visx,false,sizeof(visx));
			memset(visy,false,sizeof(visy));
			if(find(i)) break;
			mmin=1e9;
			for(int j=1;j<=n;j++) if(visx[j])
				for(int k=1;k<=n;k++) if(!visy[k]) mmin=min(mmin,tx[j]+ty[k]-g[j][k]);
			for(int j=1;j<=n;j++) if(visx[j]) tx[j]-=mmin;
			for(int j=1;j<=n;j++) if(visy[j]) ty[j]+=mmin;
		}
	}
	node op=(node){0,0};
	for(int i=1;i<=n;i++) op.x+=a[prep[i]][i],op.y+=b[prep[i]][i];
	return op;
}
 
int solve(node left,node right){
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=n;j++)
			g[i][j]=(right.y-left.y)*a[i][j]+(left.x-right.x)*b[i][j];
	node mid=KM();
	if(left==mid || mid==right) return min(left.x*left.y,right.x*right.y);
	return min(solve(left,mid),solve(mid,right));
}
 
int main(){
	scanf("%d",&T);
	node left,right;
	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];
		left=KM();
		for(int i=1;i<=n;i++) 
			for(int j=1;j<=n;j++)
				g[i][j]=-b[i][j];
		right=KM();
		printf("%d\n",solve(left,right));
    }
}

上一题