题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1625
在公司年会上,做为互联网巨头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 题目意思就是,一个n*m的矩阵的人,每个人都有一个普通的红包,现在有一种x元的高级红包,有k次机会发高级红包,只能一行或一列发,并且得到高级红包的人将没收普通红包。问最多可以发出去多少红包总金额。(给的样例也是醉了,居然有高级红包还没有普通红包多的)题目思路:有dfs搜索每行要高级红包或者不要的所以情况,在解决列变化的情况。
代码如下:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define ll long long using namespace std; ll ans,n,m,x,k; ll a[15][250],b[15][250],vis[250],all[250]; void solve() { ll used=0;//已经使用了几次高级红包 for(int i=0;i<n;i++) if(vis[i]) used++; for(int i=0;i<n;i++)//记录变化每个人金钱数 for(int j=0;j<m;j++) if(vis[i])//是高级红包就要改变原来的值 b[i][j]=x; else b[i][j]=a[i][j]; ll sum=0;//记录全部总金钱数 memset(all,0,sizeof(all));//all记录改变后,每列总金钱数 for(int j=0;j<m;j++) { for(int i=0;i<n;i++) { all[j]+=b[i][j]; sum+=b[i][j]; } } int kk=k-used;//剩下的使用高级红包的次数 sort(all,all+m);//排序,用来查找列金额是否有小于使用高级红包的 for(int i=0;i<m;i++) { if(all[i]<n*x&&kk>0)//可以对此时的i列用高级红包 { sum-=all[i]; sum+=n*x; kk--; } } ans=max(ans,sum);//记录最大值 } void dfs(int h,int sum) { if(sum>k)//超过k次 return ; if(h==n)//行数都考虑完了 solve(); else { vis[h]=1;//当前h行要高级红包 dfs(h+1,sum+1); vis[h]=0;//不要高级红包 dfs(h+1,sum); } } int main() { scanf("%lld%lld%lld%lld",&n,&m,&x,&k); memset(vis,0,sizeof(vis)); ans=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%lld",&a[i][j]); dfs(0,0); printf("%lld\n",ans); return 0; }
原文地址:https://www.cnblogs.com/xiongtao/p/9280536.html
时间: 2024-10-24 20:40:36