51Nod-1625-夹克爷发红包

来源:互联网 发布:a7r2 知乎 编辑:程序博客网 时间:2024/04/29 23:19

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 longusing 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
原创粉丝点击