您的位置:首页 > 其它

51nod 1625 夹克爷发红包

2017-11-10 19:38 197 查看
在公司年会上,做为互联网巨头51nod掌门人的夹克老爷当然不会放过任何发红包的机会。

现场有n排m列观众,夹克老爷会为每一名观众送出普通现金红包,每个红包内金额随机。

接下来,夹克老爷又送出最多k组高级红包,每高级红包会同时给一排或一列的人派发 ,每高级红包的金额皆为x。

派发高级红包时,普通红包将会强制收回。同时,每个人只能得到一个高级红包。(好小气!)

现在求一种派发高级红包的策略,使得现场观众获得的红包总金额最大。

Input
第一行为n, m, x, k四个整数。

1 <= n <= 10, 1 <= m <= 200
1 <= x <= 10^9,0 <= k <= n + m

接下来为一个n * m的矩阵,代表每个观众获得的普通红包的金额。普通红包的金额取值范围为1 <= y <= 10^9


Output
输出一个整数,代表现场观众能获得的最大红包总金额


Input示例
3 4 1 5
10 5 7 2
10 5 10 8
3 9 5 4


Output示例

78

其实具体还不是特别明白,先写下来.

首先利用二进制的特性来枚举行,对于行来说在把列的情况暴力求出来,之后选择最优情况

#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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: