题意简述:
给出一个n 代表n个数 每个数有 v(代表数的值) pos(代表数的位置 -1表示任意位置)
要求将这n个数进行排列 使得不违背位置关系
求所有相邻两个数乘积和的最大值
思路浅析:
设dp [ i ] [ j ]表示上一个用的是 i 的数并且状态为 j 的情况时的最优解,显然之后在从左往右填入数字的过程中,若当前位置已经有必填的数,那么直接状态转移,否则选一个可以放在任意位置的数,由于 i 已经确定,所以结果只会受到决策影响,具有无后效性
#include <bits/stdc++.h>
#define inf 0x7fffffff
using namespace std;
const int N = 20;
int getnum(int x)
{
int cnt = 0;
while (x)
{
cnt += x & 1;
x >>= 1;
}
return cnt;
}
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
f = (ch == '-') ? -1 : 1, ch = getchar();
while (isdigit(ch))
x = x * 10 + (ch - '0'), ch = getchar();
return x * f;
}
int n, T, cas;
int a[N], p[N];
int dp[N][1 << N];
int main()
{
int cas = 0;
int T;
T = read();
while (T--)
{
n = read();
for (int i = 0; i < n; i++)
a[i] = read(), p[i] = read();
for (int i = 0; i < n; i++)
for (int j = 0; j < (1 << n); j++)
dp[i][j] = -inf;
for (int i = 0; i < n; i++)
if (p[i] == -1 || p[i] == 0)
dp[i][1 << i] = 0;
for (int sta = 0; sta < (1 << n); sta++)
for (int i = 0; i < n; i++) //前一个
if (dp[i][sta] > -inf) /* 如果可以被继承 */
for (int j = 0; j < n; j++)
if (p[j] == -1 || p[j] == getnum(sta))
{
if (sta & (1 << j))
continue;
if (i == j)
continue;
int now = sta | (1 << j);
dp[j][now] = max(dp[j][now], dp[i][sta] + a[j] * a[i]);
}
int ans = -inf;
for (int i = 0; i < n; i++)
ans = max(ans, dp[i][(1 << n) - 1]);
printf("Case #%d:\n", ++cas);
cout << ans << endl;
}
return 0;
}