题目:http://acm.hdu.edu.cn/showproblem.php?pid=5691
带一点变形的状压dp
先预处理出所有能放在首位的状态
之后判断是如果是-1直接转移,否则要先判断现在是放第几位,相等才能转移
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
const int N=20;
const int inf=2e9;
int a[N],p[N];
int dp[1<<16][16];
int f(int x)
{
int s=0;
while(x)
{
s++;
x-=x&-x;
}
return s;
}
int main()
{
int T;
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&a[i],&p[i]);
int tot=1<<n;
for(int i=0;i<tot;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<tot;i++)
{
for(int j=0;j<n;j++)
{
if (dp[i][j]==-inf) continue;
for(int k=0;k<n;k++)
{
if (i>>k&1) continue;
if (p[k]==-1||f(i)==p[k])
dp[i|1<<k][k]=max(dp[i|1<<k][k],dp[i][j]+a[j]*a[k]);
}
}
}
int ans=-inf;
for(int i=0;i<n;i++)
ans=max(ans,dp[tot-1][i]);
printf("Case #%d:\n%d\n",ca,ans);
}
return 0;
}