51nod 1625 夹克爷发红包

题目链接

枚举+贪心。

题意:

n n n m m m列观众,给定这些观众现在手里的红包金额。老板现在最多还能发 k k k组高级红包,每组高级红包只能同时给一行或一列的人派发,同时,每个高级红包的金额都是 x x x, 每个人只能接受一个高级红包,被发高级红包的人手里的普通红包会被收走。
问,怎么派发才能使所有人拿到的红包总额最多。

题解:

这道题目如果只能分给行或者列,直接贪心就可以解决,但是,此题既能给行又能给列。每次给了行之后,由于有每个人只能收一个高级红包,导致再给列时,原来的数组已经发生了改变,也就是每次操作其实都有一定的后效性,贪心会出现偏差。
我们发现这道题目行数只有10,因此我们可以采取先枚举每行是否发高级红包的情况,再对列进行贪心。这样对行的枚举只有 2 10 = 1024 2^{10}=1024 210=1024种情况,时间复杂度可以接受。

实现细节见代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 10;
ll n, m, x, k, ans, ma[15][210], ne[15][210], l[210];
bool vis[15];
void solve(int cur) {
	ll sum = 0;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) { // 更新当前红包数组
			if (vis[i]) {
				ne[i][j] = x;
			}
			else {
				ne[i][j] = ma[i][j];
			}
		}
	}
	memset(l, 0, sizeof l);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			l[j] += ne[i][j]; // 记录每列的红包数
			sum += ne[i][j]; // 记录红包总额
		}
	}
	ll rest = k - cur; // 剩余最多可以发的高级红包数
	sort(l, l + m);
	for (int i = 0; i < m; i++) {
		if (rest > 0) {
			if (l[i] < n * x) {
				sum -= l[i];
				sum += n * x;
				rest--;
			}
		}
	}
	ans = max(ans, sum);
}
void dfs(int numx, int cur) { // numx表示当前处理的行数,cur表示当前已经发高级红包的行数
	if (cur > k) return;
	if (numx == n) {
		solve(cur);
		return;
	}
	vis[numx] = 1;
	dfs(numx + 1, cur + 1); // 枚举当前行是否发高级红包
	vis[numx] = 0;
	dfs(numx + 1, cur);
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n >> m >> x >> k;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> ma[i][j];
		}
	}
	dfs(0, 0);
	cout << ans << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值