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