度度熊是他同时代中最伟大的数学家,一切数字都要听命于他。现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了。游戏的规则十分简单,参与游戏的N个整数将会做成一排,他们将通过不断交换自己的位置,最终达到所有相邻两数乘积的和最大的目的,参与游戏的数字有整数也有负数。度度熊为了在他的数字仆人面前展现他的权威,他规定某些数字只能在坐固定的位置上,没有被度度熊限制的数字则可以自由地交换位置。
Input
第一行一个整数$T$,表示$T$组数据。
每组测试数据将以如下格式从标准输入读入:
$N$
$a_1 p_1$
$a_2 p_2$
:
$a_N P_N$
第一行,整数 $N (1 \leq N \leq 16)$,代表参与游戏的整数的个数。
从第二行到第 $(N + 1)$ 行,每行两个整数,$a_{i} (-10000 \leq a_{i} \leq 10000)$、$p_{i} (p_{i} = -1$ 或 $0 \leq p_{i} < N)$,以空格分割。$a_{i}$代表参与游戏的数字的值,$p_{i}$代表度度熊为该数字指定的位置,如果$p_{i} = -1$,代表该数字的位置不被限制。度度熊保证不会为两个数字指定相同的位置。
每组测试数据将以如下格式从标准输入读入:
$N$
$a_1 p_1$
$a_2 p_2$
:
$a_N P_N$
第一行,整数 $N (1 \leq N \leq 16)$,代表参与游戏的整数的个数。
从第二行到第 $(N + 1)$ 行,每行两个整数,$a_{i} (-10000 \leq a_{i} \leq 10000)$、$p_{i} (p_{i} = -1$ 或 $0 \leq p_{i} < N)$,以空格分割。$a_{i}$代表参与游戏的数字的值,$p_{i}$代表度度熊为该数字指定的位置,如果$p_{i} = -1$,代表该数字的位置不被限制。度度熊保证不会为两个数字指定相同的位置。
Output
第一行输出:"Case #i:"。$i$代表第$i$组测试数据。
第二行输出数字重新排列后最大的所有相邻两数乘积的和,即$max\{a_1\cdot a_2+a_2\cdot a_3+......+a_{N-1}\cdot a_N\}$。
第二行输出数字重新排列后最大的所有相邻两数乘积的和,即$max\{a_1\cdot a_2+a_2\cdot a_3+......+a_{N-1}\cdot a_N\}$。
Sample Input
2 6 -1 0 2 1 -3 2 4 3 -5 4 6 5 5 40 -1 50 -1 30 -1 20 -110 -1
题解:
我们设定dp[1<<16][16]:dp[i][j]:i为当前选取的状态并以第j个数结尾的最大值,那么答案就是 max{dp[全集][k]} k属于0到n
对于dp[i][j] , i这个状态已经填了x个数,我们准备填第x+1个数时, 如果当前位置必填某个数,那么 就只更新以规定的这个数结尾转移方程
如果没有那就 枚举那么可以任意放的数来更新相应的状态及答案
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <queue>
#include <map>
#include <stack>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-10
#define maxn 2000010
#define MOD 1000000007
int n,m;
int pos[22],a[22],num[22];
long long dp[122000][18];
int main()
{
int T,C = 1;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int k = 0;
memset(pos,INF,sizeof(pos));
memset(dp,-INF,sizeof(dp));
memset(num,0,sizeof(num));
for(int i = 0; i < n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[i] = x;
if(y != -1)
{
pos[y] = i;
num[i]++;
}
}
if(pos[0] != INF)
dp[(1<<pos[0])][pos[0]] = 0;
else
{
for(int i = 0; i < n; i++)
if(!num[i])
dp[1<<i][i] = 0;
}
for(int i = 1; i < (1<<n); i++)
{
//printf("%d\n",i);
int cnt = 0;
for(int j = 0; j < n; j++)
if(i & (1<<j))
cnt++;
if(pos[cnt] != INF)
{
cnt = pos[cnt];
for(int j = 0; j < n; j++)
if(i & (1<<j) && j != cnt)
dp[i|(1<<cnt)][cnt] = max(dp[i|(1<<cnt)][cnt],dp[i][j]+a[cnt]*a[j]);
}
else
{
for(int j = 0; j < n; j++)
if(i & (1<<j))
for(int k = 0; k < n; k++)
if(!(i & (1<<k)))
dp[i|(1<<k)][k] = max(dp[i|(1<<k)][k],dp[i][j]+a[j]*a[k]);
}
}
long long ans = -INF;
printf("Case #%d:\n",C++);
for(int i = 0; i < n; i++)
ans = max(dp[(1<<n)-1][i],ans);
printf("%I64d\n",ans);
}
return 0;
}