矩阵消除游戏
牛客链接
题号:NC200190
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
牛妹在玩一个名为矩阵消除的游戏,矩阵的大小是{n}n行{m}m列,第{i}i行第{j}j列的单元格的权值为a_{i,j}a
i,j
,牛妹可以进行{k}k个回合的游戏,在每个回合,牛妹可以选择一行或者选择一列,然后将这一行或者这一列的所有单元格中的权值变为{0}0,同时牛妹的分数会加上这一行或者这一列中的所有单元格的权值的和。
牛妹想最大化她的得分,球球你帮帮她吧!
输入描述:
第一行三个整数{n,m,k}n,m,k
接下来{n}n行每行{m}m个整数表示矩阵中各个单元格的权值。
输出描述:
输出一个整数表示牛妹能获得的最大分数。
示例1
输入
复制
3 3 2
101 1 102
1 202 1
100 8 100
输出
复制
414
备注:
1\leq n,m\leq 151≤n,m≤15
1\leq a_{i,j}\leq 1e61≤a
i,j
≤1e6
1\leq k\leq n*m1≤k≤n∗m
利用二进制串枚举所有的选择方式,
根据二进制串中1的个数确定所选行数,
根据k值,行数,确定所选列数
然后在确定选择那几行的情况下,选择和比较大的那几列
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,k;
int a[20][20];
ll sh[20];//行之和
ll sl[20];//列之和
ll ans=0;
bool b[20];//每行是否取 ,1 取 ,0 不取
int deal(int x)//将枚举的取的行的情况转换为01串
{
memset(b,0,sizeof(b));
int cnt=0,i=1;
while(x)
{
if(x&1)//如果最后一位为1
{
cnt++;
b[i]=1;//取了第i行
}
x>>=1;
i++;
}
return cnt;//1的个数即取的行数
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
sh[i]+=a[i][j];//行之和
}
}
k=min(k,min(n,m));//当行数或列数小于k时,按最小值算
int tmp=(1<<n)-1;
for(int T=0;T<=tmp;T++)
{
int numh=deal(T);//取的行数
int numl=k-numh;//取的列数
if(numl>m||numl<0) continue;//跳过不合理的情况
ll sum=0;//单次最大分数
for(int i=1;i<=n;i++)
{
if(b[i]) sum+=sh[i];//如果取第i行,加总
}
memset(sl,0,sizeof(sl));
for(int j=1;j<=m;j++)
{
for(int i=1;i<=n;i++)
{
if(!b[i]) sl[j]+=a[i][j];//如果不取第i行,才将这个值加入列之和
}
}
sort(sl+1,sl+1+m);//排序从小到大
for(int i=1,j=m;i<=numl;i++,j--)
{
sum+=sl[j];//取后几个大的
}
ans=max(ans,sum);//在多种取法中维护一个最大值
}
cout<<ans<<endl;
return 0;
}