51Nod-1625-夹克爷发红包

88 篇文章 0 订阅
57 篇文章 10 订阅

ACM模版

描述

描述

题解

做这道题,有些懵逼了我,因为一开始使用的方法是纯粹的贪心,但是偏偏有一组数据挂掉了,傻傻A不过去……
这个解法,是将行和列并在一起贪心,可能是因为行和列数据交叉,产生了后效应性,所以有的数据会挂掉。

然后,采用的枚举加贪心AC了。
因为行数最大为10,所以可以先枚举行,撑死了1024种状态,所以是可行的,然后列进行贪心,保证高级红包组数不超过k即可,最后取最大红包总和,这样子写就AC了。

代码

One:

//  WA(贴出来作为错误示例,避免以后再犯)
//#include <iostream>
//#include <cstdio>
//#include <cstring>
//
//typedef long long ll;
//
//using namespace std;
//
//const int MAXN = 13;
//const int MAXM = 203;
//
//ll matrix[MAXN][MAXM];
//ll matrixF[MAXN][MAXM]; //  红包状态,0为普通红包,1为高级红包
//ll sumN[MAXN];
//ll sumM[MAXM];
//
//int main(int argc, const char * argv[])
//{
//    freopen("/Users/zyj/Desktop/input.txt", "r", stdin);
//    
//    int n, m, x, k;
//    
//    while (cin >> n >> m >> x >> k)
//    {
//        memset(sumN, 0, sizeof(sumN));
//        memset(sumM, 0, sizeof(sumM));
//        memset(matrixF, 0, sizeof(matrixF));
//        
//        ll nx = 1ll * n * x;
//        ll mx = 1ll * m * x;
//        for (int i = 1; i <= n; i++)
//        {
//            for (int j = 1; j <= m; j++)
//            {
//                scanf("%lld", matrix[i] + j);
//                sumN[i] += matrix[i][j];
//                sumM[j] += matrix[i][j];
//            }
//        }
//        
//        while (k--)
//        {
//            //  按行查找
//            ll diffN = 0;
//            int posN = 0;
//            for (int i = 1; i <= n; i++)
//            {
//                if (mx - sumN[i] > diffN)
//                {
//                    diffN = mx - sumN[i];
//                    posN = i;
//                }
//            }
//            //  按列查找
//            ll diffM = 0;
//            int posM = 0;
//            for (int i = 1; i <= m; i++)
//            {
//                if (nx - sumM[i] > diffM)
//                {
//                    diffM = nx - sumM[i];
//                    posM = i;
//                }
//            }
//            //  列差大于行差
//            if (diffM > diffN)
//            {
//                if (diffM <= 0)
//                {
//                    break;
//                }
//                sumM[posM] = nx;
//                for (int i = 1; i <= n; i++)
//                {
//                    sumN[i] = sumN[i] + x - matrix[i][posM];
//                }
//                for (int i = 1; i <= n; i++)
//                {
//                    matrix[i][posM] = x;
//                }
//            }
//            else    //  行差大于列差
//            {
//                if (diffN <= 0)
//                {
//                    break;
//                }
//                sumN[posN] = mx;
//                for (int i = 1; i <= m; i++)
//                {
//                    sumM[i] = sumM[i] + x - matrix[posN][i];
//                }
//                for (int i = 1; i <= m; i++)
//                {
//                    matrix[posN][i] = x;
//                }
//            }
//        }
//        
//        ll ans = 0;
//        for (int i = 0; i <= n; i++)
//        {
//            ans += sumN[i];
//        }
//        
//        cout << ans << '\n';
//    }
//    
//    return 0;
//}

Two:

// AC
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>

#define  LL long long

using namespace std;

const int MAXN = 11;
const int MAXM = 201;

LL money[MAXN][MAXM];
int rlist[MAXN];

vector<LL> rowSum;
vector<LL> colSum;
vector<LL> h;       //  替换完行后,存储替换列的收益

//  检索第i种组合使用了几组高级红包
int count(int num)
{
    int ret = 0;
    while (num)
    {
        if (num & 1)
        {
            ret++;
        }
        num >>= 1;
    }
    return ret;
}

bool cmp(const LL &a, const LL &b)
{
    return a > b;
}

int main()
{
    LL n, m, x, k;
    LL sum = 0; //  所有红包总和
    scanf("%lld %lld %lld %lld", &n, &m, &x, &k);
    rowSum.resize(n, 0);
    colSum.resize(m, 0);
    h.resize(m, 0);

    for (int i = 0; i < n; ++ i)
    {
        for (int j = 0; j < m; ++ j)
        {
            scanf("%lld", &money[i][j]);
            rowSum[i] += money[i][j];
            colSum[j] += money[i][j];
            sum += money[i][j];
        }
    }
    LL row_max = 1ll * x * m;           //  整行为高级红包
    LL col_max = 1ll * x * n;           //  整列为高级红包
    LL ans = sum;                       //  初始为sum
    for (int i = 0; i < (1 << n); i++)  //  枚举所有行的组合 (1 << n)种组合
    {
        LL ret = sum;
        int idx = 0;
        int cnt = count(i);             //  高级红包使用组数
        if (k < cnt)                    //  如果超过了k,肯定不行,因为最多发k组
        {
            continue;
        }
        for (int j = 0; j < n; ++j)
        {
            if (i & (1 << j))           //  为1的标示这一行替换固定红包x,求出收益,并标示替换了哪些行
            {
                ret += row_max - rowSum[j];
                rlist[idx++] = j;       //  记录高级红包发放行数
            }
        }
        for (int j = 0; j < m; ++j)     //  求出替换完行后,每一列如果被替换所得的收益
        {
            h[j] = col_max - colSum[j];
            for (int l = 0; l < idx; ++l)
            {
                h[j] += money[rlist[l]][j] - x;
            }
        }
        sort(h.begin(), h.end(), cmp);  //  根据收益大小排序,得到最大收益的列的顺序
        for (int j = 0; j + cnt < k && h[j] > 0; ++j)   //  k-cnt剩余的就通过替换列来补充,直接加上列的收益即可
        {
            ret += h[j];
        }
        ans = max(ans, ret);            //  更新最大收益
    }
    printf("%lld\n", ans);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值