题目链接:https://nanti.jisuanke.com/t/30994
这道题出的很棒,是状压DP的入门题目,简单说一下题意
每道题会有前置的做题需求,给我们题目的价值表示方法,要我们求出做这些题目可以获得的做大价值。
由于最多只有20题,直接状压一下然后暴力就可以了。dp[i]表示状态为i时的最大价值
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
typedef unsigned int ui;
#define INF 0x3f3f3f3f
#define PB push_back
#define PI 3.1415926
#define SF scanf
#define PF printf
#define mem(a,x) memset(a,x,sizeof(a))
int gcd(int p, int q) {return q==0?p:gcd(q,p%q);}
const int maxn = 25;
struct node{
int a, b, c;
}s[maxn];
LL dp[1<<22];
int cnt[1<<22];
void init(){
for(int i = 0; i < 1<<(21); i++){
int n = i, s;
for(s = 0; n; ++s){
n &= (n-1);
}
cnt[i] = s;
}
}
int main(){
int n;
init();
// for(int i = 0; i <= 5; i++){
// cout << cnt[i] << endl;
// }
while(scanf("%d", &n) != EOF){
mem(s, 0);
mem(dp, -INF);
dp[0] = 0;
for(int i = 1; i <= n; i++){
int ss, p;
scanf("%d%d%d", &s[i].a, &s[i].b, &ss);
int sp = 0;
while(ss--){
scanf("%d", &p);
sp = sp | (1 << (p - 1));
}
s[i].c = sp;
}
LL ans = 0;
for(int i = 1; i < (1<<(n+1)); ++i){
for(int j = 1; j <= n; ++j){
if(i & (1<<(j-1))){
LL tmp = i^(1<<(j-1));
if((tmp&s[j].c) == s[j].c){
dp[i] = max(dp[i], dp[tmp] + cnt[i]*s[j].a + s[j].b);
}
}
ans = max(ans, dp[i]);
}
}
printf("%lld\n", ans);
}
return 0;
}
/*
5
5 6 0
4 5 1 1
3 4 1 2
2 3 1 3
1 2 1 4
1
-100 0 0
55
0
*/