题目描述:
时间限制:
2000ms
单点时限:
1000ms
内存限制:
256MB
-
2 3 3 1 2 3 3 1 2 2 3 1 5 5 1 2 3 4 5 5 1 2 3 4 4 5 1 2 3 3 4 5 1 2 2 3 4 5 1
样例输出
-
Case 1: 3 Case 2: 5
描述
给你一个m x n (1 <= m, n <= 100)的矩阵A (0<=aij<=10000),要求在矩阵中选择一些数,要求每一行,每一列都至少选到了一个数,使得选出的数的和尽量的小。
输入
多组测试数据。首先是数据组数T
对于每组测试数据,第1行是两个正整数m, n,分别表示矩阵的行数和列数。
接下来的m行,每行n个整数,之间用一个空格分隔,表示矩阵A的元素。
输出
每组数据输出一行,表示选出的数的和的最小值。
数据范围
小数据:1 <= m, n <= 5
大数据:1 <= m, n <= 100
题目分析:
这道题解题思路很简单,但是不容易想到。开始我只想到了对矩阵中的整数排序,然后从小到大去选,但后面怎么做就没思路了。
看了别人的解法,感觉很好。思路如下:1.对所有矩阵中的数字从小到大排序;2.按顺序去覆盖掉行和列(即保证每行和每列至少有一个数),这时记录下已选择的这些数;3.对这些筛选出的数再次排序,按照从大到小的顺序;4.按顺序处理数字,如果这个数字所在的行和列同时被其他数覆盖,则去掉这个数;如果没有则把该数进行求和。
C++代码如下:
#include <stdio.h>
#include <algorithm>
using namespace std;
struct node{
int val;
int x,y;
};
struct node nums[10001];
bool cmp1(node a, node b){
return a.val<b.val;
}
bool cmp2(node a, node b){
return a.val>b.val;
}
int main(){
int T,m,n;
scanf("%d",&T);
int i;
for(i=1;i<=T;i++){
scanf("%d %d",&m,&n);
int x,y;
for(x=0;x<m;x++)
for(y=0;y<n;y++){
int tmp;
scanf("%d",&tmp);
int index=x*n+y;
nums[index].val = tmp;
nums[index].x = x;
nums[index].y = y;
}
int xFlag[101]={0};
int yFlag[101]={0};
sort(nums,nums+(m*n),cmp1);
int index=0;
int cover=m+n;
while(cover>0){
x = nums[index].x;
y = nums[index].y;
if(xFlag[x]==0)
cover--;
if(yFlag[y]==0)
cover--;
xFlag[x]++;
yFlag[y]++;
index++;
}
sort(nums,nums+index,cmp2);
int sum=0;
int j;
for(j=0;j<index;j++){
x = nums[j].x;
y = nums[j].y;
if(xFlag[x]>1 && yFlag[y]>1){
xFlag[x]--;
yFlag[y]--;
}
else{
sum+=nums[j].val;
}
}
printf("Case %d: %d\n",i,sum);
}
return 0;
}