标签:
题解:
我们设定dp[1<<16][16]:dp[i][j]:i为当前选取的状态并以第j个数结尾的最大值,那么答案就是 max{dp[全集][k]} k属于0到n
对于dp[i][j] , i这个状态已经填了x个数,我们准备填第x+1个数时, 如果当前位置必填某个数,那么 就只更新以规定的这个数结尾转移方程
如果没有那就 枚举那么可以任意放的数来更新相应的状态及答案
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> #include<queue> #include<vector> using namespace std; const int N = 1<<17, M = 1e6+10, mod = 1000000007,inf = 1e9; typedef long long ll; ll dp[1<<17][17]; int n,a[N],p[N],H[N],F[N]; int main() { int T,cas = 1; scanf("%d",&T); while(T--) { scanf("%d",&n); memset(H,0,sizeof(H)); memset(F,-1,sizeof(F)); int tmp = 0; for(int i=0;i<n;i++) { scanf("%d%d",&a[i],&p[i]); if(p[i]!=-1) H[i] = 1,F[p[i]] = i; } for(int i=0;i<(1<<n);i++) for(int j=0;j<n;j++) dp[i][j] = -1e18; // for(int i=0;i<n;i++) // for(int j=0;j<n;j++) if(i!=j&&!H[i]&&!H[j]) dp[(1<<i)|(1<<j)][j] = a[i]*a[j], dp[(1<<i)|(1<<j)][i] = a[i]*a[j]; if(F[0]!=-1) dp[(1<<F[0])][F[0]] = 0; else { for(int i=0;i<n;i++) { if(!H[i]) dp[(1<<i)][i] = 0; } } int U = (1<<n) - 1; for(int i=1;i<=U;i++) { int counts = 0; for(int j=0;j<n;j++) if((1<<j)&(i)) counts++; if(F[counts]!=-1) { counts = F[counts]; for(int j=0;j<n;j++) if(i&(1<<j)&&counts!=j)dp[i|(1<<(counts))][counts] = max(dp[i][j]+a[j]*a[counts],dp[i|(1<<counts)][counts]); } else { for(int k=0;k<n;k++) { if((1<<k)&(i)) for(int j=0;j<n;j++) { if(!((1<<j)&i)) { dp[i|(1<<j)][j] = max(dp[i|(1<<j)][j],dp[i][k]+a[k]*a[j]); } } } } } printf("Case #%d:\n",cas++); ll ans = -1e18; for(int i=0;i<n;i++) ans = max(dp[U][i],ans) ; printf("%I64d\n",ans); } return 0; }
2016"百度之星" - 初赛(Astar Round2A)1002 / HDU 5691 状态压缩DP
标签:
原文地址:http://www.cnblogs.com/zxhl/p/5515518.html