题意:
给出n*m张牌,每张牌上有两个数字,有0和1组成,这两个数字可以互换,重新排列牌的顺序,算出每一列的和,使得这些和的最大值达到最小
解题思路:
分别计算出11,10,01,00的个数,将10,01的个数相加,这两个数实质上是一样的,因为数字可以互换,从大到小将这几个数放在一个n*m的数组中,其中在放10和01时,一行放10,一行放01
蛇行输出即可
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int str[1005][1005],s[1005][1005];
int sum[2500];
int num[20];
int main()
{
int n,m;
int all=0;
scanf("%d%d",&n,&m);
memset(num,0,sizeof(num));
int t=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&str[i][j]);
if(str[i][j]==10 || str[i][j]==1) all++;
if(str[i][j]==0) all+=2;
num[str[i][j]]++;
}
}
t=1;
int l=2;
memset(sum,0,sizeof(sum));
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
sum[t]+=str[j][i]/10;
sum[l]+=str[j][i]%10;
}
t+=2;l+=2;
}
int maxn = -50000,minx = 50000;
for(int i=1;i<=2*m;i++)
{
maxn=max(maxn,sum[i]);
minx=min(minx,sum[i]);
}
if(maxn==minx || all/(2*m)==maxn)//判断是否已经达到要求,如果是就直接输出,不用换顺序
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j==m) printf("%02d\n",str[i][j]);
else printf("%02d ",str[i][j]);
}
}
return 0;
}
int flag1=1,flag2=1;
int t1=0,t2=0;
num[1]+=num[10];
int p=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(num[11]==0) flag1=0;
if(num[11]!=0)
{
s[i][j]=11;
num[11]--;
if(num[11]==0)
{
t1=j;
}
continue;
}
if(num[1]==0) flag2=0;
if(flag1==0 && flag2==1)
{
if(p==1)
{
s[i][j]=10;
}
else
{
s[i][j]=1;
}
num[1]--;
continue;
}
if(num[1]==0) flag2=0;
if(flag1==0 && flag2==0)
{
s[i][j]=0;
num[0]--;
}
}
p = -p;
}
for(int i=1;i<=n;i++)
{
if(i%2==1)
for(int j=1;j<=m;j++)
{
if(j==m) printf("%02d\n",s[i][j]);
else printf("%02d ",s[i][j]);
}
else
for(int j=m;j>=1;j--)
{
if(j==1) printf("%02d\n",s[i][j]);
else printf("%02d ",s[i][j]);
}
}
return 0;
}