題面
題目描述
MM 雖然一輩子只要一個,但是也得早點解決。於是,n 個光棍們自發組成了一個光棍組織 (ruffian organization,By Wind 亂譯)。現在,光棍們打算分成幾個小組,並且分頭爲 找 MM 事
業做貢獻(For example:searching,hunting……By Wind 亂譯)。 對於這 n 個光棍的任意一個組合,都有一個被稱爲“和諧度”的東西,現在,他們想知道, 如何分組
可以使和諧度總和最大。 每個光棍都必須屬於某個分組,可以一個人一組。
輸入格式
第 1 行爲 n,接下來 2^n-1 行,按照 2 進制給出每個分組的和諧度。
(比如接下來第 5 行,也就是總共第六行,2 進製爲 00000101,則表示第 1 個人和第 3 個人 這個分組的和諧度,第 31 行則爲 1~5 在一起的和諧度)
題解
這道題目是一個子集DP,每一個子集可以用一個n位二進制數表示。對於任意一個集合i都是由它的子集任意組合形成的。
狀態
我們設 代表狀態爲i的最大和諧度。
狀態轉移方程
code
#include<bits/stdc++.h>
using namespace std;
inline long long read(){
long long num=0;
char c=' ';
bool flag=true;
for(;c>'9'||c<'0';c=getchar())
if(c=='-')
flag=false;
for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
return flag ? num : -num;
}
const int maxn=18;
int n;
long long f[1<<maxn];
void init(){
n=read();
for(int i=1;i<1<<n;i++)
f[i]=read();
}
void dp(){
for(int i=1;i<1<<n;i++)
for(int j=(i-1)&i;j;j=(j-1)&i)
//非常經典,枚舉子集
f[i]=max(f[i],f[j]+f[i-j]);
printf("%lld\n",f[(1<<n)-1]);
}
int main(){
init();
dp();
return 0;
}