题面
大秦 为你打开 题目传送门
思路
这道题说数字分两种,固定的和非固定的,让你给非固定的排列,让相邻数字的乘积和最大。
同样数据范围很小,$n$ 只有 $16$ ,显然还是状压 DP,状态同样是排好了什么什么数字,最后一个排好的数字是什么。因为我们默认是把要排的数字一位一位排下来,这样就更方便递推。
这道题相对简单,初始化要分情况:
- 第一个固定,只有固定的数字是第一
- 第一个不固定,谁都可以是第一个
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include<bits/stdc++.h> using namespace std;
int n; int a[20], p[20];
int b[20]; int dp[1 << 20][20];
void Input() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d%d", &a[i], &p[i]); if (p[i] != -1) b[p[i]] = 1; } }
void Init() { for (int i = 0; i < (1 << n); i++) { for (int j = 1; j <= n; j++) { dp[i][j] = -2e9; } } if (b[0]) { for (int i = 1; i <= n; i++) { if (p[i] == 0) { dp[(1 << (i - 1))][i] = 0; } } } else { for (int i = 1; i <= n; i++) { if (p[i] == -1) { dp[(1 << (i - 1))][i] = 0; } } } }
void Work() { Init(); for (int mask = 1; mask < (1 << n); mask++) { for (int ed = 1; ed <= n; ed++) { if (!(mask & (1 << (ed - 1)))) continue; int pos = 0; for (int i = 1; i <= n; i++) { if (mask & (1 << (i - 1))) { pos++; } } for (int nt = 1; nt <= n; nt++) { if (mask & (1 << (nt - 1))) continue; if (p[nt] == pos || (b[pos] == 0 && p[nt] == -1)) { dp[mask | (1 << (nt - 1))][nt] = max(dp[mask | 1 << (nt - 1)][nt], dp[mask][ed] + a[ed] * a[nt]); } } } } int ans = -2e9; for (int i = 1; i <= n; i++) { ans = max(ans, dp[(1 << n) - 1][i]); } printf("%d", ans); }
int main() { Input(); Work(); return 0; }
|