#include<iostream>
typedef struct
{
int x,y,key,p;
} Max;
void QuickSortRowP(Max R[100][100],int x,int s, int t)
{
int i=s, j=t;
Max tmp, tra;
if(s<t)
{
tmp=R[x][s];
while(i!=j)
{
while(j>i&&R[x][j].p>=tmp.p)
{
j--;
}
tra=R[x][i];
R[x][i]=R[x][j];
R[x][j]=tra;
while(i<j&&R[x][i].p<tmp.p)
{
i++;
}
tra=R[x][j];
R[x][j]=R[x][i];
R[x][i]=tra;
}
R[x][i]=tmp;
QuickSortRowP(R,x,s,i-1);
QuickSortRowP(R,x,i+1,t);
}
}
void QuickSortCol(Max R[100][100],int y,int s, int t)
{
int i=s, j=t;
Max tmp, tra;
if(s<t)
{
tmp=R[s][y];
while(i!=j)
{
while(j>i&&R[j][y].key>=tmp.key)
{
j--;
}
tra=R[i][y];
R[i][y]=R[j][y];
R[j][y]=tra;
while(i<j&&R[i][y].key<tmp.key)
{
i++;
}
tra=R[j][y];
R[j][y]=R[i][y];
R[i][y]=tra;
}
R[i][y]=tmp;
QuickSortCol(R,y,s,i-1);
QuickSortCol(R,y,i+1,t);
}
}
int main()
{
int T,m,n,t,i,j,ii,jj,coun,LACK,NEWLACK,flag,sum[100],OPER[100],RF[100][100];
Max conum[100][100],CHOOSE[100],TEMP;
std::cin>>T;
for(t=0; t<T; ++t)
{
std::cin>>m>>n;
for(i=0; i<m; ++i) //input
{
for(j=0; j<n; ++j)
{
std::cin>>conum[i][j].key;
conum[i][j].p=0;
conum[i][j].x=i;
conum[i][j].y=j;
}
}
if(m>n)
{
for(j=0; j<n; ++j) //reverse
{
for(i=j+1; i<m; ++i)
{
conum[j][i].p=0;
ii=conum[j][i].y;
conum[j][i].y=conum[i][j].x;
conum[i][j].x=ii;
ii=conum[j][i].x;
conum[j][i].x=conum[i][j].y;
conum[i][j].y=ii;
ii=conum[j][i].key;
conum[j][i].key=conum[i][j].key;
conum[i][j].key=ii;
}
}
i=m;
m=n;
n=i;
}
for(j=0; j<n; ++j)//col sort <- key step
{
QuickSortCol(conum,j,0,m-1);
}
for(j=0; j<n; ++j)//p increase initialize
{
for(i=0; i<m; ++i)
{
conum[i][j].p=conum[i][j].key-conum[0][j].key;
}
}
for(j=0; j<n; ++j)//CHOOSE and OPER initialize
{
CHOOSE[j]=conum[0][j];
OPER[j]=0;
}
coun=0;
for(j=0; j<n; ++j) //LACK initialize
{
for(i=0; i<m; ++i)
{
if(CHOOSE[j].x==i)
{
OPER[i]+=1;
}
}
}
for(i=0; i<m; ++i)
{
if(OPER[i])
{
coun+=1;
OPER[i]=0;
}
}
LACK=m-coun;
coun=0;
for(i=0; i<m; ++i)
{
QuickSortRowP(conum,i,0,n-1);
}
for(i=0; i<m; ++i)//RF initialize
{
for(j=0; j<n; ++j)
{
RF[i][j]=1;
}
}
for(j=0; j<n; ++j)
{
RF[0][j]=0;
}
while(LACK)
{
for(j=0; j<n; ++j)
{
for(i=0; i<m; ++i)
{
if(RF[i][j]==1)
{
TEMP=CHOOSE[conum[i][j].y];//TEMP initialize
CHOOSE[conum[i][j].y]=conum[i][j];
flag=conum[i][j].y;//flag initialize
//compute new lack
for(jj=0; jj<n; ++jj)
{
for(ii=0; ii<m; ++ii)
{
if(CHOOSE[jj].x==ii)
{
OPER[ii]+=1;
}
}
}
for(ii=0; ii<m; ++ii)
{
if(OPER[ii])
{
coun+=1;
OPER[ii]=0;
}
}
NEWLACK=m-coun;//NEWLACK initialize
coun=0;
//
if(NEWLACK<LACK)
{
LACK=NEWLACK;
RF[i][j]=0;
continue;
}
else
{
CHOOSE[flag]=TEMP;
}
}
}
}
}
sum[t]=0;//sum initialize
for(j=0; j<n; ++j)
{
sum[t]+=CHOOSE[j].key;
}
}//T!! do not delete
for(t=0; t<T; ++t)
{
std::cout<<"Case "<<t+1<<": "<<sum[t]<<std::endl;
}
}//main!! do not delete
矩阵采用结构体,记录所在的x轴、y轴位置,key值和一个辅助变量p,p记录垂直排序后每一列的递增情况。
变量说明:
T,m,n//循环次数,行,列 ,t,i,j,ii,jj// 计数 coun,LACK,NEWLACK,OPER[100]//用于计算未覆盖的行数 flag//标记 RF[100][100]//辅助矩阵 sum[100]//记录结果 conum[100][100]//结构矩阵 CHOOSE[100]//选出的元素
没有刻意遵循某种算法,总体上是按照排序优先的原则进行遍历,个人认为行和列中较大的值代表必须选出的元素的总数。
大致思想是先考虑每一列再考虑每一行。首先使列数n恒大于等于行数m(不满足则转置),对每一列垂直排序,最上方一行即为每一列最小值的组合并作为CHOOSE[]的初始值。如果CHOOSE[]没有覆盖每一行,对除第一行外,对列的递增情况进行水平排序;计算未覆盖行数LACK,判断是否覆盖了每一行,如果没有覆盖全部行则循环更新CHOOSE[]和LACK直到完全覆盖每一行为止。
自己测试多组数据都是对的,不知道为什么WA,就当写着玩儿了~