UVA 1508 - Equipment 状态压缩 枚举子集 dfs

来源:互联网 发布:vscode markdown 插件 编辑:程序博客网 时间:2024/05/16 13:56

UVA 1508 - Equipment 状态压缩 枚举子集 dfs

ACM

题目地址:UVA 1508 - Equipment--PDF

题意: 
给出n个5元组,从中选出k组,使得这些组中5个位置,每个位置上最大数之和最大。

分析: 
想了好久...最后还是参考了别人的题解... 
不过思路很棒,值得学习。

由于n的范围为1,10000,所以从n考虑是很难解出来的。 
于是我们从5元组考虑。 
每组5元组,最后可能被选择作为和的一部分,就是[11111],即[全部被选中做和]的子集,一共有31种情况。 
我们只要预处理这31种情况可能得到的最大的和。然后dfs遍历子集就行了。具体见代码。

代码

/**  Author:      illuz <iilluzen[at]gmail.com>*  File:        1508.cpp*  Create Date: 2014-06-28 20:55:20*  Descripton:   */#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int N = 10010;int n, t, k, ans;int m[5], r[N][5], mmax[40];int dfs(int S, int num) {// find num different subset in S, return the max sumif (num == 0) {return 0;}int tmp = 0;for (int S0 = S; S0; S0 = (S0-1)&S) {tmp = max(tmp, mmax[S0] + dfs((S0^S), num - 1));}return tmp;}int main() {scanf("%d", &t);while (t--) {memset(m, 0, sizeof(m));// inputscanf("%d%d", &n, &k);for (int i = 0; i < n; i++) {for (int j = 0; j < 5; j++) {scanf("%d", &r[i][j]);m[j] = max(m[j], r[i][j]);}}if (k >= 5) {// just the maxint sum = 0;for (int i = 0; i < 5; i++) {sum += m[i];}printf("%d\n", sum);} else {memset(mmax, 0, sizeof(mmax));for (int i = 0; i < n; i++) {// for every onefor (int S = 0; S <= 31; S++) {// every situation, 00000 to 11111int tmp = 0;for (int k = 0; k < 5; k++) {if (S&(1<<k)) {tmp += r[i][k];}mmax[S] = max(mmax[S], tmp);// update the max of every situation}}}printf("%d\n", dfs(31, k));// find the max sum in 11111}}return 0;}


3 0
原创粉丝点击