1. 程式人生 > >2017盛大遊戲杯 零件組裝(狀態壓縮DP之巧妙枚舉子集)

2017盛大遊戲杯 零件組裝(狀態壓縮DP之巧妙枚舉子集)

mst print scan shu for ble pre 一個 clas

題目鏈接:2017盛大遊戲杯 零件組裝

題意:

有n個零件,給你相鄰關系和排斥關系,每兩塊零件組裝起來有一個代價,問最少的代價總和是多少。

題解:

考慮狀態壓縮,dp[i]表示i這個集合為一個零件塊。

那麽要枚舉一下i的子集。O(3^n).

先要預處理一下每個集合的排斥個數和相鄰個數,然後容斥一下就可以了。

技術分享
 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define F(i,a,b) for(int i=a;i<=b;++i)
 4 #define count(x) __builtin_popcount(x)
 5
using namespace std; 6 7 const int N=14; 8 int t,n,a[N][N],b[N][N],U; 9 int f[1<<N],g[1<<N],dp[1<<N]; 10 11 int main(){ 12 scanf("%d",&t); 13 while(t--) 14 { 15 scanf("%d",&n),U=(1<<n)-1; 16 F(i,0,n-1)F(j,0,n-1)scanf("%d",&a[i][j]);
17 F(i,0,n-1)F(j,0,n-1)scanf("%d",&b[i][j]); 18 mst(dp,63),mst(f,0),mst(g,0),dp[0]=0; 19 F(i,0,U)F(ii,0,n-1)F(jj,ii+1,n-1) 20 if((i&(1<<ii))&&(i&(1<<jj)))f[i]+=a[ii][jj],g[i]+=b[ii][jj]; 21 F(i,0,n-1)dp[1<<i]=0; 22 F(i,0,U)for
(int j=i;j;j=(j-1)&i) 23 { 24 int ii=j,jj=j^i; 25 if(f[i]-f[ii]-f[jj]) 26 dp[i]=min(dp[i],dp[ii]+dp[jj]+(g[i]-g[ii]-g[jj])*max(count(ii),count(jj))); 27 } 28 printf("%d\n",dp[U]); 29 } 30 return 0; 31 }
View Code

2017盛大遊戲杯 零件組裝(狀態壓縮DP之巧妙枚舉子集)