水状压dp.
dp(x, s) = max{ dp( x - 1, s - {h} ) } + 奖励(假如拿到的) (h∈s). 时间复杂度O(n * 2^n)
----------------------------------------------------------------------------------
#include<bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < n; ++i)
#define clr(x, c) memset(x, c, sizeof(x))
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); e++)
#define b(i) (1 << (i))
using namespace std;
const int maxn = 22;
int dp[2][b(maxn)], s[maxn][maxn], n;
vector<int> ok[maxn];
vector< pair<int, int> > rew[maxn];
int main() {
freopen("test.in", "r", stdin);
clr(dp, 0);
int b;
cin >> n >> b;
rep(i, n) {
ok[i].clear();
rew[i].clear();
}
while(b--) {
int p, k, a;
scanf("%d%d%d", &p, &k, &a); p--;
rew[p].push_back(make_pair(k, a));
}
int cur = 0, p = 1;
rep(i, n) rep(j, n) scanf("%d", s[i] + j);
rep(j, n) {
dp[cur][b(j)] = s[j][0];
foreach(it, rew[0]) if(s[j][0] >= it->first)
dp[cur][b(j)] += it->second;
}
rep(t, b(n)) {
int cnt = 0;
rep(i, n) if(t & b(i)) cnt++;
if(cnt--) ok[cnt].push_back(t);
}
for(int i = 1; i < n; ++i) {
swap(cur, p);
foreach(it, ok[i]) {
rep(j, n) if(b(j) & *it)
dp[cur][*it] = max(dp[cur][*it], dp[p][*it ^ b(j)] + s[j][i]);
foreach(t, rew[i]) if(dp[cur][*it] >= t->first)
dp[cur][*it] += t->second;
}
}
cout << dp[cur][b(n) - 1] << "\n";
return 0;
}
----------------------------------------------------------------------------------
3446: [Usaco2014 Feb]Cow Decathlon
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 58 Solved: 41
[Submit][Status][Discuss]
Description
FJ有N(1 <= N <= 20)头奶牛,编号1至N。FJ提供N种不同的技能供奶牛们学习,每头奶牛只能学习一门技能,每门技能都要有奶牛学习。 第i头奶牛学习第j门技能,FJ得到的分数S[i][j],1<=S[i][j]<=1000。此外还有B(1 <= B <= 20)个奖励,第i个奖励的格式是: Pi 、Ki 、Ai,表示的意义是:如果学习完前Ki门技能后的总得分(包括额外的奖励得分)不少于Pi,那么FJ还会得到额外的Ai分。那么FJ应该如何安排奶牛学习技能,才能使得最后的总得分最高?
Input
第一行,N和B。 接下来有B行,每行三个整数:Pi 、Ki 、Ai。1 <= Pi <= 40000,1 <= Ai <= 1000。 接下来有N行N列的二维数组,表示S[i][j]。1 <= S[i][j] <= 1000。
Output
Sample Input
3 1
2 7 6
5 1 7
2 2 4
4 2 1
Sample Output
17
奶牛1学习技能1,奶牛2学习技能3,奶牛3学习技能2。
HINT
Source