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