编程之美 格格取数 C语言版本

题目描述:

时间限制: 2000ms
单点时限: 1000ms
内存限制: 256MB

描述

给你一个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



样例输入
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

题目分析:

这道题解题思路很简单,但是不容易想到。开始我只想到了对矩阵中的整数排序,然后从小到大去选,但后面怎么做就没思路了。

看了别人的解法,感觉很好。思路如下: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;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值