题意:
大概是有n个数,正数负数都有,n<16,有些数字被固定位置只能放固定位置,其他数字随意放,问何时相邻两数乘积之和何时最大,输出和。
思路:
看到n<16很容易想到状态压缩,dp[i][j]表示状态i时,第j数放最后的最大值。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int dp[1<<20][20];
int a[20];
int p[20];
int num(int x) {
int ans=0;
while(x&-x) {
ans++;
x-=x&-x;
}
return ans;
}
int main()
{
int t,n;
int kase=0;
//cout << "!!!!!!!!" << num(5) <<endl;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&a[i],&p[i]);
for(int i=0;i<(1<<n);i++)
for(int j=0;j<n;j++)
dp[i][j]=-INF;
for(int i=0;i<n;i++)
if(p[i]==0||p[i]==-1)
dp[1<<i][i]=0;
for(int i=0;i<(1<<n);i++) {
for(int j=0;j<n;j++) {
if(dp[i][j]!=-INF) {
for(int k=0;k<n;k++) {
if(k!=j&&((1<<k&i)==0)&&(num(i)==p[k]||p[k]==-1)) {
dp[i|(1<<k)][k]=max(dp[i|(1<<k)][k],dp[i][j]+a[j]*a[k]);
}
}
}
}
}
int maxn=-INF;
for(int i=0;i<n;i++) {
maxn=max(maxn,dp[(1<<n)-1][i]);
}
printf("Case #%d:\n",++kase);
printf("%d\n",maxn);
}
return 0;
}