bzoj2064: 分裂(集合DP)

  ......咸鱼了将近一个月,因为沉迷ingress作业越来越多一直没时间搞OI呜呜呜

  题目大意:有一个初始集合(n个元素)和一个目标集合(m个元素)(1<=n,m<=10),两个操作

         操作①将集合里的两个数合成一个数

         操作②将集合的一个数分成两个数

       问对初始集合最少进行几次操作可以到达目标集合

  ...从来没做过集合DP题,看见这题一脸懵逼>_<

  看了题解之后目瞪口呆,思路又神,又学会了新技巧(可能是我以前比较傻才不会QAQ

  显然最多的次数就是将初始集合全部合成一个数然后再分成目标集合,也就是次数上界为n+m-2

  如果我们可以找到初始集合的某个子集的元素和目标集合的某个子集的元素和相等,那么我们可以少合一次,少分一次,也就是说我们每多找到一个元素和相等的子集我们的次数就可以-2。换句话说把初始集合和目标集合分成尽量多的子集让这些子集都能对应(子集元素和相等),如果能分成x个子集那么次数就是n+m-2x

  所以问题转化成怎么分最多子集能相对应。f[S1][S2]为把S1和S2最多能分成几个能相对应的子集(子集元素和相等)。

  当S1的元素和!=S2的元素和,就没法用上所有元素分成相对应的子集,那我们就枚举S1中的元素i或S2中的一个元素j,就有f[S1][S2]=max(f[S1^i][S2],f[S1][S2^j])

  当S1的元素和==S2的元素和,我们可以用上全部元素,在这时候我们要是去掉其中一个元素,肯定会少一个子集,于是我们还是枚举S1中的元素i或S2中的一个元素j,就有f[S1][S2]=max(f[S1^i][S2],f[S1][S2^j])+1

  新技巧:......原来枚举子集用二进制枚举就可以了,以前我怎么这么傻QAQ

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n,m,sum1[1024],sum2[1024],f[1024][1024];
int lowbit(int x){return x&-x;}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d",&sum1[1<<i]);
    scanf("%d",&m);
    for(int i=0;i<m;i++)scanf("%d",&sum2[1<<i]);
    for(int i=1;i<(1<<n);i++)sum1[i]=sum1[i^lowbit(i)]+sum1[lowbit(i)];
    for(int i=1;i<(1<<m);i++)sum2[i]=sum2[i^lowbit(i)]+sum2[lowbit(i)];
    for(int i=1;i<(1<<n);i++)
    for(int j=1;j<(1<<m);j++)
    {
        for(int k=0;k<max(n,m);k++)
        {
            if(i&(1<<k))f[i][j]=max(f[i^(1<<k)][j],f[i][j]);
            if(j&(1<<k))f[i][j]=max(f[i][j^(1<<k)],f[i][j]);
        }
        if(sum1[i]==sum2[j])f[i][j]++;
    }
    printf("%d\n",n+m-2*f[(1<<n)-1][(1<<m)-1]);
}

时间: 2025-01-14 23:01:13

bzoj2064: 分裂(集合DP)的相关文章

bzoj2064分裂(dp)

题目大意: 给定一个初始集合和目标集合,有两种操作:1.合并集合中的两个元素,新元素为两个元素之和 2.分裂集合中的一个元素,得到的两个新元素之和等于原先的元素.要求用最小步数使初始集合变为目标集合,求最小步数. 其中初始集合和目标集合的元素个数都不超过10个 这是一道非常值得纪念的好题 首先一看到这个数据范围,第一反应就是状压dp了 我们首先这么考虑 如果说直接暴力的合并和分裂的话,最多需要的次数是\(n+m-2\)次,那么我们是不是可以在这个基础上进行优化呢.举个例子来看\(1,5,7,2\

【状压dp】Bzoj2064 分裂

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

bzoj2064: 分裂(状压dp)

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

[BZOJ2064]分裂 状压dp

2064: 分裂 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 656  Solved: 404[Submit][Status][Discuss] Description 背景: 和久必分,分久必和... 题目描述: 中国历史上上分分和和次数非常多..通读中国历史的WJMZBMR表示毫无压力. 同时经常搞OI的他把这个变成了一个数学模型. 假设中国的国土总和是不变的. 每个国家都可以用他的国土面积代替, 又两种可能,一种是两个国家合并为1个,那么新

[BZOJ2064]分裂

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

uva10817集合dp

题意:某校有s个课程m个教师和n个求职者,已知每人的工资和能教的课程,要求支付最少的工资使得每门课都至少有两名教师教学.在职教必须雇佣. 思路:d(i,s0,s1,s2)表示已经雇了i个人且授课状态为(s0,s1,s2),还需要多少钱.其中s0表示没有人授课的课程集合,s1表示只有一个人授课的课程集合,s2表示有2个老师授课的课程集合.(因为不知道要雇佣多少老师,所以状态为当雇佣了i人时还需要多少钱,而不是雇佣了i人花了多少钱). #include<bits/stdc++.h> using n

集合DP 点集匹配问题

刘汝佳大白书p61页 #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> using namespace std; #define INF 0x3f3f3f3f #define N 21 struct point { double x, y, z; } P[N]; double x[N], y[N]; doub

E. The Values You Can Make 背包,同时DP

http://codeforces.com/problemset/problem/688/E 题目需要在n个数中找出一个集合,使得这个集合的和为val,然后问这些所有集合,能产生多少个不同的和值. 题解是直接两个同时dp,设dp[j][h]表示主集合的和为j,能否产生h这个数字. 把他们看作是两个集合,对于每个数,都可以放在第一个集合,或者放在第一个集合后,再放入第二个集合. #include <cstdio> #include <cstdlib> #include <cst

poj 2836 Rectangular Covering(状态压缩dp)

Description n points are given on the Cartesian plane. Now you have to use some rectangles whose sides are parallel to the axes to cover them. Every point must be covered. And a point can be covered by several rectangles. Each rectangle should cover