Matrix \operatorname{Matrix} Matrix
题目链接: jzoj 1228 \operatorname{jzoj\ 1228} jzoj 1228
题目
给你一个 N ∗ M N*M N∗M 的矩阵,矩阵里面的元素要么是正数,要么是负数,它们的绝对值不大于 10000 10000 10000 。现在你可以对矩阵进行两种操作:
- 将某一列的元素全部取反。
- 将某一行的元素全部取反。
你可以执行任意次操作。
Task:通过以上两种操作如果可以将整个矩阵的元素全变为正数的话,则输出最少的操作次数,否则输出“impossible”(不包括双引号)。
输入
输入文件的第一行有两个整数
n
n
n 和
m
(
1
≤
n
,
m
≤
1000
)
m(1≤n,m≤1000)
m(1≤n,m≤1000) ,表示矩阵的大小。
接下来有
N
N
N 行,每行
M
M
M 个数,每个数之间有一个空格。
输出
通过以上两种操作如果可以将整个矩阵的元素全变为正数的话,则输出最少的操作次
数,否则输出“impossible”(不包括双引号)。
样例输入
2 4
3 7 -6 1
-2 -6 8 -4
样例输出
2
数据范围
对于
40
%
40\%
40% 的数据,
1
≤
N
,
M
≤
10
1≤N,M≤10
1≤N,M≤10
对于
100
%
100\%
100% 的数据,
2
≤
N
,
M
≤
1000
2≤N,M≤1000
2≤N,M≤1000
思路
这道题是一道贪心。
我们枚举每一行,看每一行有多少个是负数。
如果有一半以上是负数,就取反,不然就把这一行上所有是负数的列给取反。
如果有要取反两次的,就说明没有答案。
代码
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
ll n, m, ans, a[1001][1001], sum, now, i;
bool in[1001], yes;
int main()
{
// freopen("matrix.in","r",stdin);
// freopen("matrix.out","w",stdout);
scanf("%lld %lld", &n, &m);//读入
for (int k = 1; k <= n; k++)
for (int j = 1; j <= m; j++) {
scanf("%lld", &a[k][j]);//读入
now += a[k][j];
if (a[k][j] < 0) sum += -a[k][j];
else sum += a[k][j];
}
while (++i)
{
if (i > n) i %= n;
if (yes) break;
int tot = 0;
for (int j = 1; j <= m; j++)
if (a[i][j] < 0) tot++;//统计负数
if (tot >= m / 2) {//负数有一半
for (int j = 1; j <= m; j++) {
now -= a[i][j] * 2;
a[i][j] = -a[i][j];//取反
}
ans++;//答案加上
}
else for (int j = 1; j <= m; j++)//纵向取反
if (a[i][j] < 0) {
if (in[j]) {//没有结果
yes = 1;
break;
}
else {
in[j] = 1;
for (int k = 1; k <= n; k++) {
now -= a[k][j] * 2;
a[k][j] = -a[k][j];
}
ans++;
}
}
if (now == sum) break;//全都是正的
}
ans = min(ans, n + m - ans);
if (yes) printf("impossible");//输出
else printf("%lld", ans);
// fclose(stdin);
// fclose(stdout);
}