题目
Problem Description
度度熊是他同时代中最伟大的数学家,一切数字都要听命于他。现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了。游戏的规则十分简单,参与游戏的N个整数将会做成一排,他们将通过不断交换自己的位置,最终达到所有相邻两数乘积的和最大的目的,参与游戏的数字有整数也有负数。度度熊为了在他的数字仆人面前展现他的权威,他规定某些数字只能在坐固定的位置上,没有被度度熊限制的数字则可以自由地交换位置。
Input
第一行一个整数T,表示T组数据。
每组测试数据将以如下格式从标准输入读入:
N
a1p1
a2p2
:
aNPN
第一行,整数 N(1≤N≤16),代表参与游戏的整数的个数。
从第二行到第 (N+1) 行,每行两个整数,ai(−10000≤ai≤10000)、pi(pi=−1 或 0≤pi
分析
这道题一开始看见数据这么小,搜索?16!太大了
还有一种解决NP问题的算法就是状态压缩DP了,再仔细看了一下题,感觉很像哈密顿路,只是规定了第pi个经过的点必须是i而已。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[1<<16][16];
int a[20],p[20],ans,T,rp[20],n,cnt[1<<16];
bool vis[20];
template<class T>
void Read(T &x){
char c;
bool f=0;
while(c=getchar(),c!=EOF){
if(c=='-')
f=1;
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
if(f)
x=-x;
return;
}
}
}
int lowbit(int x){
return x&-x;
}
void dp(){
int s,t=1<<n,j,q;
int i;
if(vis[0])
f[1<<rp[0]][rp[0]]=0;
else
for(i=0;i<n;i++)
if(p[i]==-1)
f[1<<i][i]=0;
for(s=1;s<t;s++){
cnt[s]=cnt[s^lowbit(s)]+1;
if(vis[cnt[s]-1]){
if(!(s&(1<<rp[cnt[s]-1])))
continue;
q=s^(1<<rp[cnt[s]-1]);
for(i=0;i<n;i++)
f[s][rp[cnt[s]-1]]=max(f[s][rp[cnt[s]-1]],f[q][i]+a[i]*a[rp[cnt[s]-1]]);
}
else
for(i=0;i<n;i++)
if(p[i]==-1&&(s&(1<<i)))
for(q=s^(1<<i),j=0;j<n;j++)
f[s][i]=max(f[s][i],f[q][j]+a[j]*a[i]);
}
for(i=0;i<n;i++)
ans=max(ans,f[t-1][i]);
}
int main()
{
Read(T);
int cnt=0;
while(T--){
Read(n);
int i;
ans=0x80808080;
memset(f,0xa0,sizeof f);
memset(vis,0,sizeof vis);
for(i=0;i<n;i++){
Read(a[i]),Read(p[i]);
if(~p[i])
vis[p[i]]=1,rp[p[i]]=i;
}
if(n==1)
ans=0;
else
dp();
printf("Case #%d:\n%d\n",++cnt,ans);
}
}