题目链接:
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 = 22; const int INF = 2e9; int dp[1 << 16][22]; int cnt[1 << 16]; int a[maxn], p[maxn],f[maxn]; int n; void pre() { for (int i = 0; i < (1 << 16); i++) { cnt[i] = 0; for (int j = 0; j < 16; j++) { if (i&(1 << j)) cnt[i]++; } } } void init() { for (int i = 0; i < (1 << n); i++) { for (int j = 0; j <= n; j++) { dp[i][j] = -INF; } } memset(f, -1, sizeof(f)); } int main() { pre(); int tc,kase=0; scanf("%d", &tc); while (tc--) { scanf("%d", &n); init(); for (int i = 0; i < n; i++) { scanf("%d%d", a + i, p + i); if (p[i] != -1) f[p[i]] = i; } a[n] = 0; p[n] = n; dp[0][n] = 0; for (int i = 0; i < (1 << n); i++) { int sum = cnt[i]; for (int j = 0; j <= n; j++) { if ((i&(1 << j)) == 0&&j!=n) continue; //被限制的点: if (f[sum] != -1) { if ((i&(1 << f[sum])) == 0) { dp[i | (1 << f[sum])][f[sum]] = max(dp[i | (1 << f[sum])][f[sum]], dp[i][j]+a[j]*a[f[sum]]); } } else { //可以自由移动的点 for (int k = 0; k < n; k++) { if (i&(1 << k)) continue; if (p[k] ==-1) { dp[i | (1 << k)][k] = max(dp[i | (1 << k)][k], dp[i][j] + a[j] * a[k]); } } } } } int ans = -INF; for (int j = 0; j < n; j++) ans = max(ans, dp[(1 << n) - 1][j]); printf("Case #%d: ", ++kase); printf("%d ", ans); } return 0; }
再一发:
#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-9; const double PI = acos(-1.0); //start---------------------------------------------------------------------- const int maxn=17; LL dp[1<<maxn][maxn]; LL arr[maxn]; int pos[maxn],mp[maxn]; int sumv[1<<maxn]; int n; void pre(){ clr(sumv,0); for(int i=0;i<(1<<maxn);i++){ for(int j=0;j<maxn;j++){ if(i&(1<<j)){ sumv[i]++; } } } } void init(){ clr(mp,-1); } int main() { pre(); int tc,kase=0; scf("%d",&tc); while(tc--){ scf("%d",&n); init(); rep(i,0,n){ scf("%lld%d",&arr[i],&pos[i]); if(pos[i]>=0) mp[pos[i]]=i; } rep(i,0,(1<<maxn)) rep(j,0,maxn) dp[i][j]=-INFL; if(mp[0]>=0){ dp[1<<mp[0]][mp[0]]=0; }else{ for(int i=0;i<n;i++){ if(pos[i]>=0) continue; dp[1<<i][i]=0; } } rep(i,1,(1<<n)){ rep(j,0,n){ if(!(i&(1<<j))) continue; if(mp[sumv[i]-1]>=0&&mp[sumv[i]-1]!=j) continue; rep(k,0,n){ if(k==j||!(i&(1<<k))) continue; if(mp[sumv[i^(1<<j)]-1]>=0&&mp[sumv[i^(1<<j)]-1]!=k) continue; dp[i][j]=max(dp[i][j],dp[i^(1<<j)][k]+arr[k]*arr[j]); } } } LL ans=-INFL; rep(i,0,n) ans=max(ans,dp[(1<<n)-1][i]); prf("Case #%d: ",++kase); prf("%lld ",ans); } return 0; } //end-----------------------------------------------------------------------