牛客练习赛58 C-矩阵消除游戏(二进制枚举)

传送门

题意:

在这里插入图片描述

思路:

数据只有15,直接枚举所有情况即可
通过二进制枚举行,每次枚举的意义是枚举几行以及枚举的哪几行
假设该次枚举cnt行,那么剩下的肯定都选的是列,只用找到枚举完行之后,剩余每列之和的前k-cnt大的加在总和里即可
__builtin_popcount(i)计算i的二进制中1的个数
一些__builtin_函数
为什么不能贪心,每次找行或列的最大值
因为选列行或列之和,对列或行有影响,即选不同的行产生的最大不一样
例如:

3 3 2
101 101 1
10  5   1
2   10  1

按照贪心的话应该选第一行,然后第二列 结果是203+15=218
但是先选第一行,然后第二行的结果是113+116=229
显然贪心有问题

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <map>
#include <queue>
#include <set>
#include <stack>
typedef long long ll;
#define PII make_pair
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int MAXN=1e5+50;
const int inf=0x3f3f3f3f;
const int M=5000*4;
int n,m,k;
int a[20][20];
ll h[20];//每一行的和
ll p[20];//每一列的和
int main()
{   
    scanf("%d%d%d",&n,&m,&k);
    ll sum=0;
    rep(i,1,n)
     rep(j,1,m){
        scanf("%d",&a[i][j]);
        h[i]+=a[i][j];
        sum+=a[i][j];
     }
     if(k>=n||k>=m){
        printf("%lld\n",sum);
        return 0;
     }
     k=min(k,min(n,m));
     ll ans=0;
     for(int i=0;i<(1<<n);i++){
        int cnt=__builtin_popcount(i);//有cnt个1,要选cnt行
        if(cnt>k)continue;
        sum=0;
        memset(p,0,sizeof(p));//记得清零
        for(int j=0;j<n;j++)if(i&(1<<j))sum+=h[j+1];

        for(int j=0;j<n;j++)
            for(int kk=1;kk<=m;kk++)if(!(i&(1<<j)))p[kk]+=a[j+1][kk];//在选cnt行之后,每一列的和

        sort(p+1,p+m+1);
        for(int j=1;j<=k-cnt;j++)
            sum+=p[m-j+1];
        ans=max(ans,sum);
     }

     printf("%lld\n",ans);
    return 0;
} 

发布了142 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44091178/article/details/104582456