分析:
看到题目第一感觉状压DP,由于状压DP要能转移,所以需要知道当前用到的点的集合中最后一个用的点的编号。
所以转移方程就出来了:
dp[i][j]=max(dp[i xor (1<<j)][k]+a[k]∗a[j],dp[i][j])
题目中还有一个条件,有一个固定位置,所以在转移的时候特判一下就好了。
复杂度:
o(2n∗n2)
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
using namespace std;
typedef long long LL;
typedef vector <int> VI;
typedef pair <int,int> PII;
#define FOR(i,x,y) for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const LL inf = 1LL<<50;
const int maxn = 1<<16;
LL val[16],dp[maxn][16];
int n,pos[16],id[16];
void work(){
int m = 1<<n;
FOR(i,0,m) FOR(j,0,n) dp[i][j] = -inf;
if(id[0] != -1) dp[1<<id[0]][id[0]] = 0;
else{
FOR(i,0,n) dp[1<<i][i] = 0;
}
FOR(i,1,m){
int wei = __builtin_popcount(i); wei--;
FOR(j,0,n){
if((i&1<<j) == 0) continue;
if(id[wei] != -1 && id[wei] != j) continue;
int mx = i^(1<<j);
FOR(k,0,n){
if((mx&1<<k) == 0) continue;
dp[i][j] = max(dp[i][j],dp[mx][k]+val[j]*val[k]);
}
}
}
LL ans = -inf;
FOR(i,0,n) ans = max(ans,dp[m-1][i]);
printf("%I64d\n",ans);
}
int main(){
int T,tCase = 0; scanf("%d",&T);
while(T--){
printf("Case #%d:\n",++tCase);
scanf("%d",&n);
memset(id,-1,sizeof(id));
FOR(i,0,n){
scanf("%I64d%d",&val[i],&pos[i]);
if(pos[i] != -1) id[pos[i]] = i;
}
work();
}
return 0;
}