HLOJ#483 光棍組織

題面

題目描述
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都是由它的子集任意組合形成的。

狀態

我們設f[i] 代表狀態爲i的最大和諧度。

狀態轉移方程

f[i]=max{f[j]+f[ij]}     ji

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章