Matrix

Matrix ⁡ \operatorname{Matrix} Matrix

题目链接: jzoj 1228 ⁡ \operatorname{jzoj\ 1228} jzoj 1228

题目

给你一个 N ∗ M N*M NM 的矩阵,矩阵里面的元素要么是正数,要么是负数,它们的绝对值不大于 10000 10000 10000 。现在你可以对矩阵进行两种操作:

  1. 将某一列的元素全部取反。
  2. 将某一行的元素全部取反。

你可以执行任意次操作。
Task:通过以上两种操作如果可以将整个矩阵的元素全变为正数的话,则输出最少的操作次数,否则输出“impossible”(不包括双引号)。

输入

输入文件的第一行有两个整数 n n n m ( 1 ≤ n , m ≤ 1000 ) m(1≤n,m≤1000) m(1n,m1000) ,表示矩阵的大小。
接下来有 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 1N,M10
对于 100 % 100\% 100% 的数据, 2 ≤ N , M ≤ 1000 2≤N,M≤1000 2NM1000

思路

这道题是一道贪心。

我们枚举每一行,看每一行有多少个是负数。
如果有一半以上是负数,就取反,不然就把这一行上所有是负数的列给取反。
如果有要取反两次的,就说明没有答案。

代码

#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);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值