前言:因为消除每一行必然会影响每一列(不像题解13),而又看到最多只有15行15列,所以贪心算法中直接先把要消除的行考虑好(用01串枚举),然后直接看剩余元素列和最大就好了

思路&AC代码:

#include<iostream>
#include<algorithm>//sort()
#include<cstring>//memset()
using namespace std;
int a[20][20]={0,0};//记录每个点的权重
int lie[20];//计算各列除去被清空元素以外元素的和
int n;int m;int cnt;//为了让cnt直接被deal操作,直接写成全局变量了
int deal(int t)
{    
    int sum=0;cnt =0;
    for(int i=1;i<=n;i++)
    {
        if(  ( ( t>>(i-1) )& 1 ) ==1  )//一定要打好括号,不要赌自己优先级是否考虑对了。t位移i-1位刚好是从右到左依次看每一位是否为1
        {
            for(int j=1;j<=m;j++){sum+=a[i][j];}
            cnt++;//记录行操作的次数
        }
        else 
        {
           for(int j=1;j<=m;j++) {lie[j]+=a[i][j];}//是+=。如果没消除这一行,就把每一列的和中加上这一行的各个元素。思路十分巧妙
        }
    }
    return sum;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);
    int k;cin>>n>>m>>k;int tsum=0;int res=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];tsum+=a[i][j];
        }
    }
    if(k>=n || k>=m){cout<<tsum;return 0;}//如果能全取就全取,取所有行或所有列
    for(int c=0;c<= ((1<<n)-1);c++)//这里直接用二进制位01来表示选哪些行,如有3行,1<<3=1000;1000-1=0111;刚好有枚举三行的情况,至于为什么不枚举到k行就结束?因为全部枚举完起到了把枚举过的行的元素置0的操作,还可以直接计算好剩余各列的权值和。不然的话,又要做清0某行的操作,还要循环再去加上各列权值,这就多此一举了
    {
        memset(lie, 0, sizeof(lie));//每次列举一种行数就清空列
        int sum=deal(c);//行的权值和
        if(cnt>k || k-cnt>m){continue;}//如果操作超过了k次或者列不够操作,就跳过
        sort(lie+1,lie+1+m);//从小到大排序(排序),接下来再倒序输出就好了
        for(int j=m;j>m-(k-cnt);j--)//植树原理,刚好输出前(k-cnt)个最大的,也可以用for(int i=1,j=m;i<=k-cnt;i++,j--)
        {
            sum+=lie[j];//把去掉了拿走的行的元素的列前k-cnt个加起来
        }
        res=max(sum,res);
    }    
    cout<<res;
        
    return 0;
}