题意
元素个数为
n
n
的 数组,有些数字位置在数列中的位置已经确定,现在要任意的将没确定位置的数排进数列,求
max{a1a2+a2a3+a3a4+...+an−1an}
m
a
x
{
a
1
a
2
+
a
2
a
3
+
a
3
a
4
+
.
.
.
+
a
n
−
1
a
n
}
。
1≤n≤16
1
≤
n
≤
16
思路
在数列已经被钦定的位置标上数的下标,然后按顺序添数用 dpi,j d p i , j 排进选了 i i 这些数,最后一个数是 时的最大值。在从 0 0 枚举到 的时候,只要预处理一个 cnt c n t 表示某一个数二进制有多少个 1 1 <script type="math/tex" id="MathJax-Element-537">1</script> ,就可以随时知道接下来该填哪个位置,就可以判断改选什么数了。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define tomax(a,b) (a=max(a,b))
#define lowbit(x) ((x)&-(x))
typedef long long LL;
using namespace std;
int a[18],p[18],det[18];
int cnt[(1<<16)+3],bin[(1<<16)+3];
LL dp[(1<<16)+3][18];
int main()
{
FOR(i,1,1<<16)cnt[i]=cnt[i-lowbit(i)]+1;
FOR(i,1,16)bin[1<<i]=i;
int T;
scanf("%d",&T);
FOR(Ti,1,T)
{
int n;
scanf("%d",&n);
memset(det,-1,sizeof(det));
memset(dp,0xc0,sizeof(dp));
FOR(i,0,n-1)
{
scanf("%d%d",&a[i],&p[i]);
if(~p[i])det[p[i]]=i;
}
if(~det[0])dp[1<<det[0]][det[0]]=0;
else FOR(i,0,n-1)if(!~p[i])dp[1<<i][i]=0;
FOR(i,0,(1<<n)-1)
for(int j=i;j;j^=lowbit(j))
{
if(!~det[cnt[i]])
for(int k=(~i)&(1<<n)-1;k;k^=lowbit(k))
{
if(!~p[bin[lowbit(k)]])
tomax(dp[i^lowbit(k)][bin[lowbit(k)]],dp[i][bin[lowbit(j)]]+a[bin[lowbit(j)]]*a[bin[lowbit(k)]]);
}
else tomax(dp[i^(1<<det[cnt[i]])][det[cnt[i]]],dp[i][bin[lowbit(j)]]+a[bin[lowbit(j)]]*a[det[cnt[i]]]);
}
LL ans=-9e18;
FOR(i,1,n)ans=max(ans,dp[(1<<n)-1][i]);
printf("Case #%d:\n%lld\n",Ti,ans);
}
return 0;
}