时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个NxN的整数矩阵,小Hi每次操作可以选择两列,将这两列中的所有数变成它的相反数。
小Hi可以进行任意次操作,他的目标是使矩阵中所有数的和尽量大。你能求出最大可能的和吗?
输入
第一行一个整数N。
以下N行,每行N个整数Aij。
对于30%的数据,2 ≤ N ≤ 10
对于100%的数据,2 ≤ N ≤ 200, -1000 ≤ Aij ≤ 1000
输出
最大可能的和
样例输入
4 -1 1 1 2 -2 -3 1 2 -3 -2 1 2 -4 -1 1 2
样例输出
27
/
分析:对于一组数,他们的相反数之和是他们和的相反数。所以对于N*N矩阵,把某一列设置为相反数后求总和,实际上可以改为把某一列的和设置为相反数后求总和。
这里要求一次把某两列设置为相反数,可以先将矩阵所有列的和保存在一个vector之中,然后对vector排序。此时可以确定排序后的容器,前两个元素必然是矩阵中列之和最小的两个列。如果这两个元素相加之和小于0,那么可以确定把这两列设置为相反数后其和大于0,即可以增加矩阵的总和。将这两列设置为相反数之和,重新排序容器,继续上一步的判断,直到最小的两个元素之和大于0,意味着此时如果设置某两列为相反数,只会减小就矩阵的总和,则停止循环,获取此时容器中所有元素的和,既是矩阵可能的最大的和。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int getcolsum(int **p, int N, int col) //获取矩阵列的和
{
int sum = 0;
for(int i = 0; i != N; ++i)
{
sum += p[i][col];
}
return sum;
}
int main()
{
int N;
cin >> N;
//开辟二维数组
int **arr = new int*[N];
for(int i = 0; i != N; ++i)
{
arr[i] = new int[N];
for(int j = 0; j != N; ++j) //输入元素
cin >> arr[i][j];
}
vector<int> colsum; //获取矩阵每一列的和
for(int i = 0; i != N; ++i)
colsum.push_back(getcolsum(arr, N, i));
sort(colsum.begin(), colsum.end()); //对每一列和进行排序
while(colsum[0] + colsum[1] < 0) //当排序后最小的两列和相加小于0,此时把这两列设置为相反数可以
{ //增大矩阵和,把此两列设置为相反数,即把列之和设置为相反数
colsum[0] = -colsum[0];
colsum[1] = -colsum[1];
sort(colsum.begin(), colsum.end()); //从新排序继续循环
}
//获取矩阵和
int sum = 0;
for(int i = 0; i != colsum.size(); ++i)
sum += colsum[i];
cout << sum << endl;
//释放二维数组
for(int i = 0; i != N; ++i)
delete []arr[i];
delete []arr;
return 0;
}