參考了: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對其它的同行或者同列的數有一定影響,而因為先後騷的順序不一樣而導致最後結果可能有差異,不過這種到底是哪個正確本人還搞不清楚,暫且就按標程的走,但是對於這兩份代碼的正確性我也沒法保證,因為腦子不行+懶,以後有時間再去證證,可能只是很簡單的證明吧。