题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5691
题解:
和tsp用的状压差不多,就是固定了一些访问顺序。
dp[i][j]表示前cnt个点中布满状态i且最后一个为j的状态的最大乘积和。
则有dp[i|(1<<k)][k]=max(dp[i|(1<<k)][k],dp[i][j]+a[j]*a[k])。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std; const int maxn = ;
const int INF = 2e9;
int dp[ << ][];
int cnt[ << ];
int a[maxn], p[maxn],f[maxn];
int n; void pre() {
for (int i = ; i < ( << ); i++) {
cnt[i] = ;
for (int j = ; j < ; j++) {
if (i&( << j)) cnt[i]++;
}
}
} void init() {
for (int i = ; i < ( << n); i++) {
for (int j = ; j <= n; j++) {
dp[i][j] = -INF;
}
}
memset(f, -, sizeof(f));
} int main() {
pre();
int tc,kase=;
scanf("%d", &tc);
while (tc--) {
scanf("%d", &n);
init();
for (int i = ; i < n; i++) {
scanf("%d%d", a + i, p + i);
if (p[i] != -) f[p[i]] = i;
}
a[n] = ; p[n] = n;
dp[][n] = ;
for (int i = ; i < ( << n); i++) {
int sum = cnt[i];
for (int j = ; j <= n; j++) {
if ((i&( << j)) == &&j!=n) continue;
//被限制的点:
if (f[sum] != -) {
if ((i&( << f[sum])) == ) {
dp[i | ( << f[sum])][f[sum]] =
max(dp[i | ( << f[sum])][f[sum]], dp[i][j]+a[j]*a[f[sum]]);
}
}
else {
//可以*移动的点
for (int k = ; k < n; k++) {
if (i&( << k)) continue;
if (p[k] ==-) {
dp[i | ( << k)][k] = max(dp[i | ( << k)][k], dp[i][j] + a[j] * a[k]);
}
}
}
}
}
int ans = -INF;
for (int j = ; j < n; j++) ans = max(ans, dp[( << n) - ][j]);
printf("Case #%d:\n", ++kase);
printf("%d\n", ans);
}
return ;
}
再一发:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII; const int INF=0x3f3f3f3f;
const LL INFL=10000000000000000LL;
const double eps=1e-; const double PI = acos(-1.0); //start---------------------------------------------------------------------- const int maxn=; LL dp[<<maxn][maxn];
LL arr[maxn];
int pos[maxn],mp[maxn];
int sumv[<<maxn];
int n; void pre(){
clr(sumv,);
for(int i=;i<(<<maxn);i++){
for(int j=;j<maxn;j++){
if(i&(<<j)){
sumv[i]++;
}
}
}
} void init(){
clr(mp,-);
} int main() {
pre();
int tc,kase=;
scf("%d",&tc);
while(tc--){
scf("%d",&n);
init();
rep(i,,n){
scf("%lld%d",&arr[i],&pos[i]);
if(pos[i]>=) mp[pos[i]]=i;
} rep(i,,(<<maxn)) rep(j,,maxn) dp[i][j]=-INFL;
if(mp[]>=){
dp[<<mp[]][mp[]]=;
}else{
for(int i=;i<n;i++){
if(pos[i]>=) continue;
dp[<<i][i]=;
}
} rep(i,,(<<n)){
rep(j,,n){
if(!(i&(<<j))) continue;
if(mp[sumv[i]-]>=&&mp[sumv[i]-]!=j) continue;
rep(k,,n){
if(k==j||!(i&(<<k))) continue;
if(mp[sumv[i^(<<j)]-]>=&&mp[sumv[i^(<<j)]-]!=k) continue;
dp[i][j]=max(dp[i][j],dp[i^(<<j)][k]+arr[k]*arr[j]);
}
}
} LL ans=-INFL;
rep(i,,n) ans=max(ans,dp[(<<n)-][i]);
prf("Case #%d:\n",++kase);
prf("%lld\n",ans); }
return ;
} //end-----------------------------------------------------------------------