ACM-ICPC 2018 南京賽區網路預賽 : E. AC Challenge(狀壓DP)
阿新 • • 發佈:2019-02-12
這道題出的很棒,是狀壓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 */