bzoj2064分裂 关于一类状压问题的总结

来源:互联网 发布:eraser软件 编辑:程序博客网 时间:2024/05/16 05:23

2064: 分裂

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 660  Solved: 406
[Submit][Status][Discuss]

Description

背景: 和久必分,分久必和。。。 题目描述: 中国历史上上分分和和次数非常多。。通读中国历史的WJMZBMR表示毫无压力。 同时经常搞OI的他把这个变成了一个数学模型。 假设中国的国土总和是不变的。 每个国家都可以用他的国土面积代替, 又两种可能,一种是两个国家合并为1个,那么新国家的面积为两者之和。 一种是一个国家分裂为2个,那么2个新国家的面积之和为原国家的面积。 WJMZBMR现在知道了很遥远的过去中国的状态,又知道了中国现在的状态,想知道至少要几次操作(分裂和合并各算一次操作),能让中国从当时状态到达现在的状态。

Input

第一行一个数n1,表示当时的块数,接下来n1个数分别表示各块的面积。 第二行一个数n2,表示现在的块,接下来n2个数分别表示各块的面积。

Output

一行一个数表示最小次数。

Sample Input

1 6
3 1 2 3

Sample Output

2
数据范围:
对于100%的数据,n1,n2<=10,每个数<=50
对于30%的数据,n1,n2<=6,

HINT

Source

和谐社会模拟赛


好题好题。可以当作状态压缩的一种DP模板。

1.      最终状态是2^n-1

2.      各个子集之间的答案互不影响,且对于每种状态S,f(S)=f(T)+f(S-T),其中T为S子集

3.      一个合法状态S的最差答案=S包含1的个数-a(或+a)

4.      目标最小化(最大化)

在这个时候,划分子集划分得越多越好。所以我们把问题转化为把S分成尽量多的合法状态。于是我们设f[S]为将S划分成最多的子集个数。方程有f[S]=max{f[T]+f[S-T],f[S]}(注意S,T,S-T都必须是合法状态),其中T为S子集,[]为布尔表达式。最后的答案就是n-a*f[2^n-1]

这样子初步设计出了O(3^n)的算法

特别地,若f[2^i]=0,也就是若S只由单个1组成时不是合法状态吗,并且去掉一个1之后也不是合法状态,我们可以令f[S]=max{f[S-2^i]}+[S为合法状态],其中S的第i位是1,也就是把S划分成单个1和其余部分。因为此时S-2^i是一个最优子结构。因为任意一个其余的子集一定包含在这些子集之中。这样的算法可以优化到O(n2^n)(此方法慎用)

套到本题,我们把新旧设计在从一个状态中。我们定义一个状态的sum值为新的面积减去旧的面积,那么当sum是0的时候,显然是一个合法的变化状态,假设这个时候新旧加起来是n个数,我们把新的并起来,在逐一拆回旧的,那么一共经历了n-2次变换。这个和上述模板不谋而合。

然后就可以开心的状压了。

相同类型的题目还有bzoj3900,可以去试看看

 

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<vector>using namespace std;const int N = 3000000;int read(){    char ch = getchar(); int x = 0, f = 1;    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}    while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}    return x * f;}int n, m, bin[30], sum[N], f[N]; int main(){    bin[0] = 1; for(int i = 1;i <= 25; ++i) bin[i] = bin[i - 1] << 1;     n = read();    for(int i = 0;i < n; ++i) sum[bin[i]] = read();     m = read();    for(int i = 0;i < m; ++i) sum[bin[i + n]] = -read();    n += m;    for(int i = 1;i < bin[n]; ++i) {        int t = i & (-i);        sum[i] = sum[t] + sum[i ^ t];        for(int j = 0; j < n; ++j)        if(i & bin[j]) f[i] = max(f[i], f[i ^ bin[j]]);        if(!sum[i]) ++f[i];    }    printf("%d\n", n - (f[bin[n] - 1] << 1));    return 0;}


阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 4438x6拿去不谢 敬谢不敏 3344vva拿走不谢 214hu拿走不谢 ygyg66拿走不谢 不用谢英语 不用谢英文 038ee拿走不谢 907ee拿走不谢 不用谢 80abab拿走不谢 拿走不谢 门卫爷爷你不能谢里面 4hu51拿走不谢 爸爸你不能谢里面 大恩不言谢 不谢 2019网址拿走不谢 125sihu打开看不用谢 2018在线网站拿走不谢 2019在线网站拿走不谢 2019男人都懂的网站拿走不谢 我不是歌神谷小白 不谷 一谷不登 美谷朱里不能出声在线播放 完谷不化 不违农时谷不可胜食也 谷神不死 从来不哭by小竖谷阳 想不想修真隐神谷需要条件 不色谷h 想不想修真怎么进隐神谷 回到西游当大神 独谷不醉 不能动 负如来不负卿 此生不负你情深华笙 南心不负 此生不负你深情 不负荣光不负你