状态压缩DP。
dp[i][j]表示前cnt个位置放了i状态的那些数字,cnt位置放的是j这个数字的最大价值。其中cnt为i二进制中1的个数。
#include<cstdio> #include <iostream> #include<cstring> #include<cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; long long INF = 99999999999999999; long long dp[70000][20]; int n; long long a[20]; int p[20],f[20], g[20]; int main() { int T; int Case = 1; scanf("%d", &T); while (T--) { scanf("%d", &n); memset(f, 0, sizeof f); memset(g, 0, sizeof g); for (int i = 1; i <= n; i++) { scanf("%lld%d", &a[i], &p[i]); if (p[i] == -1) continue; p[i]++; f[p[i]] = i; g[i] = 1; } for (int i = 0; i<(1 << n); i++) for (int j = 0; j <= n; j++) dp[i][j] = -INF; for (int j = 1; j <= n; j++) { if (g[j] == 1 && p[j] != 1) continue; dp[1 << (j - 1)][j] = 0; } for (int i = 1; i<(1 << n); i++) { int cnt = 0; for (int j = 0; j<n; j++) if ((i&(1 << j)) !=0) cnt++; for (int j = 1; j <= n; j++) { if (dp[i][j] == -INF) continue; if (f[cnt + 1] != 0) { dp[i | (1 << (f[cnt + 1] - 1))][f[cnt + 1]] = max(dp[i | (1 << (f[cnt + 1] - 1))][f[cnt + 1]], dp[i][j] + a[f[cnt + 1]] * a[j]); continue; } for (int k = 1; k <= n; k++) { if (((1 << (k - 1))&i) != 0) continue; if (g[k] == 1) continue; dp[i | (1 << (k - 1))][k] = max(dp[i | (1 << (k - 1))][k], dp[i][j] + a[k] * a[j]); } } } long long ans = -INF; for (int j = 1; j <= n; j++) { ans = max(ans, dp[(1 << n) - 1][j]); } printf("Case #%d: ", Case++); printf("%lld ", ans); } return 0; }