题意:给定n * m(n m <= 100)的矩阵,没分数字的绝对值<=100,现在想通过翻转一行或者一列的重复操作(不能出现相同的操作),使得所有行和列的
和都>=0,问任意一组能满足条件的行列翻转方法。
题解:cf 上好像每次比赛都有贪心的样子。因为n m <= 100,所以一共最多有200次翻转操作,每次更新矩阵。但是这样可能会有一种操作重复,但是最多
两次因为贪心能保证这样的性质,随后再搞一下就好了。
Sure原创,转载请注明出处。
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
using namespace std;
const int maxn = 102;
int map[maxn][maxn],rr[maxn << 1],rc[maxn << 1];
int m,n,tr,tc;
void read()
{
tr = tc = 0;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
}
}
return;
}
int check()
{
int bjr = -1,bjc = -1;
int sr = 0,sc = 0;
for(int i=1;i<=m;i++)
{
int sum = 0;
for(int j=1;j<=n;j++)
{
sum += map[i][j];
}
if(sum < sr)
{
sr = sum;
bjr = i;
}
}
for(int j=1;j<=n;j++)
{
int sum = 0;
for(int i=1;i<=m;i++)
{
sum += map[i][j];
}
if(sum < sc)
{
sc = sum;
bjc = j;
}
}
if(sr == 0 && sc == 0) return 0;
return sr < sc ? bjr : (-bjc);
}
int gao(int *s,int num)
{
int l = 0,top = 0;
while(l < num)
{
int r = l+1;
int cnt = 1;
while(r < num && s[l] == s[r])
{
r++;
cnt++;
}
if(cnt & 1)
{
s[top++] = s[l];
}
l = r;
}
return top;
}
void solve()
{
while(true)
{
int val = check();
if(val == 0) break;
if(val > 0)
{
rr[tr++] = val;
for(int i=1;i<=n;i++)
{
map[val][i] = -map[val][i];
}
}
else
{
val = -val;
rc[tc++] = val;
for(int i=1;i<=m;i++)
{
map[i][val] = -map[i][val];
}
}
}
sort(rr , rr + tr);
sort(rc , rc + tc);
tr = gao(rr , tr);
tc = gao(rc , tc);
printf("%d",tr);
for(int i=0;i<tr;i++)
{
printf(" %d",rr[i]);
}
puts("");
printf("%d",tc);
for(int i=0;i<tc;i++)
{
printf(" %d",rc[i]);
}
puts("");
return;
}
int main()
{
while(~scanf("%d %d",&m,&n))
{
read();
solve();
}
return 0;
}