编程之美 格格取数问题

参考了:http://blog.csdn.net/liuguidongliuguidong/article/details/23474573

现在还无法确定这个方法是否正确,反正是AC了,参考处的主页君的代码自己去看看吧,我写出我的两个版本的代码,然后引出问题所在。

1.WA代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
struct node{
    int v;
    int x,y;
}nums[10001];
bool cmp(node a, node b){
    return a.v < b.v;
}
int main(){
    int T,m,n;
    int minSum = 0;
    int cx[101],cy[101];
    int cover = 0,index;
    scanf(“%d”,&T);
    for(int t = 1;t <= T;t++){
        scanf(“%d %d”,&m,&n);
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                scanf(“%d”,&nums[i * n + j].v);
                nums[i * n + j].x = i;
                nums[i * n + j].y = j;
                cy[j] = 0;
            }
            cx[i] = 0;
        }
         minSum = 0;
         cover = m + n;
         index = 0;
         sort(nums,nums + (m * n),cmp);
         while(cover > 0){
             cover -= (cx[nums[index].x] == 0) ? 1 : 0;
             cover -= (cy[nums[index].y] == 0) ? 1 : 0;
             cx[nums[index].x]++;
             cy[nums[index++].y]++;
         }
         for(int i = 0;i < index;i++){
             if(cx[nums[i].x] > 1 && cy[nums[i].y] > 1){
                 cy[nums[i].y]–;
                 cx[nums[i].x]–;
             }else{
                 minSum += nums[i].v;
             }
         }

         printf(“Case %d: %d\n”,t,minSum);
    }
    return 0;
}

2.AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
struct node{
    int v;
    int x,y;
}nums[10001];
bool cmp(node a, node b){
    return a.v < b.v;
}
bool cmp1(node a,node b){
    return a.v > b.v;
}

int main(){
    int T,m,n;
    int minSum = 0;
    int cx[101],cy[101];
    int cover = 0,index;
    scanf(“%d”,&T);
    for(int t = 1;t <= T;t++){
        scanf(“%d %d”,&m,&n);
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                scanf(“%d”,&nums[i * n + j].v);
                nums[i * n + j].x = i;
                nums[i * n + j].y = j;
                cy[j] = 0;
            }
            cx[i] = 0;
        }
        sort(nums,nums + (m * n),cmp);
        minSum = 0;
        cover = m + n;
        index = 0;
        while(cover > 0){
            if(cx[nums[index].x] == 0)cover–;
            if(cy[nums[index].y] == 0)cover–;
            cx[nums[index].x]++;
            cy[nums[index++].y]++;
        }
        sort(nums,nums + index,cmp1);
        for(int i = 0;i < index;i++){
            if(cx[nums[i].x] > 1 && cy[nums[i].y] > 1){
                cy[nums[i].y]–;
                cx[nums[i].x]–;
            }else{
                minSum += nums[i].v;
            }
        }

        printf(“Case %d: %d\n”,t,minSum);
    }
    return 0;
}

    不同点仅在蓝色部分,下面分析下为什么蓝色部分会导致两种结果。

    个人猜测是标程有问题。解题思路大概是:

        a.先对方格中的所有数从小大待排序;

        b.然后对方格从小到大覆盖,直至所有的行和列都覆盖即停;

        c.对被选来覆盖的那些数进行再次排序,但是是从大到小排序(关键);

        d.然后对排序后的数从大到小扫,去掉多余的,即其所在行和列都已经有其他的数。

        e.去掉的同时也计算该留下的那些数的总和即可。

    我的第一份WA的代码看上去跟第二份没什么区别,第一份没有对选中的数再次排序,第二份对选中的数排序了。这操作之后对数组唯一的区别在于对相同值的数的排列,比如:设有三个数a{v=3,x=0,y=0}、b{v=3,x=1,y=1}、c{v=3,x=1,y=2}:

        a.在我的WA代码里:只排了一次序,没搞错的话顺序应该是:a-b-c,然后就开始从后往前扫,一直删除,这样最先遭殃的是c,然后b,最后才是a;

        b.而在我的AC代码里:除了最先的升序排序外,后面还进行了对已选的数在进行一次降序排序,虽然那三个数最后的结果还是a-b-c的顺序,但是我是从前往后扫,结果就              是最先遭殃的应该是a,然后是b,最后才是c.

    在这种情况下,有可能的情况就是a,b,c对其它的同行或者同列的数有一定影响,而因为先后骚的顺序不一样而导致最后结果可能有差异,不过这种到底是哪个正确本人还搞不清楚,暂且就按标程的走,但是对于这两份代码的正确性我也没法保证,因为脑子不行+懒,以后有时间再去证证,可能只是很简单的证明吧。

    原文作者:neoliang007
    原文地址: https://blog.csdn.net/stillfantacy/article/details/23523885
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞