折半搜索+状态压缩【P3067】 [USACO12OPEN]平衡的奶牛群Balanced Cow S…

Description

给n个数,从中任意选出一些数,使这些数能分成和相等的两组。

求有多少种选数的方案。

Input

第\(1\)行:一个整数\(N\)

第\(2\)到\(N+1\)行,包含一个整数\(m_i\)

Output

一行:平衡的集合的个数.

看到题的一瞬间数据范围?

\(N \leq 20?\)状压!

明显直接做过不去,选择折半搜索.

折半搜索的话会有三种情况

  • 一.选择当前位置
  • 二.选择当前位置,给第一组.
  • 三.选择当前位置,给第二组.

然后直接跑折半搜索+状压即可.

存储类似链式前向星,应该不是很难理解,就不过多解释了.

然后就枚举状态即可,可是直接枚举到\(2^n-1\)显然会\(T\)掉.

由于我们后半截的状态已知,所以说,我们只需要枚举前一半的状态即可.

注意要\(sort\)找到两边力气值相等的.

其他的就不太难理解了,如果不能理解的话可以私信我 qwq.

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#define N 10000008
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,w[28],mid,head[N];
struct cod{int u,val;}e[200008],edge[N];
int v[N],ans,tot,ttt,sta,cnt;
bool vis[2500000];
void dfs1(int dep,int sum,int state)
{
    if(dep>mid)
    {
        edge[++tot].u=head[state];
        edge[tot].val=sum;
        head[state]=tot;
        return;
    }
    dfs1(dep+1,sum,state);
    dfs1(dep+1,sum+w[dep],state|(1<<(dep-1)));
    dfs1(dep+1,sum-w[dep],state|(1<<(dep-1)));
}
void dfs2(int dep,int sum,int state)
{
    if(dep>n)
    {
        e[++ttt].u=state;
        e[ttt].val=sum;
        return;
    }
    dfs2(dep+1,sum,state);
    dfs2(dep+1,sum+w[dep],state | (1<<(dep-1)));
    dfs2(dep+1,sum-w[dep],state | (1<<(dep-1)));
}
inline bool ccp(const cod&a,const cod&b)
{
    return a.val<b.val;
}
int main()
{
    in(n);mid=(n+1)>>1;sta=(1<<n)-1;
    for(R int i=1;i<=n;i++)in(w[i]);
    dfs1(1,0,0);dfs2(mid+1,0,0);
    sort(e+1,e+ttt+1,ccp);
    for(R int i=0;i<=(1<<mid);i++)
    {
        R int cnt=0;
        for(R int j=head[i];j;j=edge[j].u)
            v[++cnt]=edge[j].val;
        sort(v+1,v+cnt+1);
        R int pos=1;
        if(v[1]>e[ttt].val)break;
        for(R int j=1;j<=ttt;j++)
        {
            while(pos<=cnt and v[pos]<e[j].val)pos++;
            if(pos>cnt)break;
            if(v[pos]==e[j].val)
                vis[i|e[j].u]=true;
        }
    }
    for(R int i=1;i<=sta;i++)
        if(vis[i])ans++;
    printf("%d",ans);
}
/*
10
5 8 16 17 25 83 24 7 8 20

89
*/

原文地址:https://www.cnblogs.com/-guz/p/9826717.html

时间: 2024-08-30 14:53:48

折半搜索+状态压缩【P3067】 [USACO12OPEN]平衡的奶牛群Balanced Cow S…的相关文章

hdu 1429 胜利大逃亡(续)【广度优先搜索+状态压缩】

胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5411    Accepted Submission(s): 1863 Problem Description Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)-- 这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了

POJ 1351 Number of Locks (记忆化搜索 状态压缩)

Number of Locks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 1161   Accepted: 571 Description In certain factory a kind of spring locks is manufactured. There are n slots (1 < n < 17, n is a natural number.) for each lock. The height

hiho 1170(机器人-记忆化搜索+状态压缩)

#1170 : 机器人 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 小冰的N个机器人兄弟排成一列,每个机器人有一个颜色.现在小冰想让同一颜色的机器人聚在一起,即任意两个同颜色的机器人之间没有其他颜色的的机器人. 假设任意相邻的两个机器人可以交换位置,请问最少需要多少次交换? 输入 第一行为一个整数T,为数据组数,之后每组数据两行. 第一行为N和K,表示机器人的个数与颜色的总数. 接下来一行N个数,第i个数表示第i个机器人的颜色,取值范围为1到K. 输出 对于每组数

hdu 1429 胜利大逃亡(续) 搜索+状态压缩,,不错的题。

胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5860    Accepted Submission(s): 2046 Problem Description Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)-- 这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了

Luogu3067 平衡的奶牛群 Meet in the middle

题意:给出$N$个范围在$[1,10^8]$内的整数,问有多少种取数方案使得取出来的数能够分成两个和相等的集合.$N \leq 20$ 发现爆搜是$O(3^N)$的,所以考虑双向搜索. 先把前$3^\frac{N}{2}$搜完,然后每一次搜出后$3^\frac{N}{2}$的时候,枚举前面的$2^\frac{N}{2}$,每一个对应一下看有没有和为$0$的方案即可.复杂度为$O(6^\frac{N}{2})$,虽然不开O2过不去qwq 1 #include<bits/stdc++.h> 2 u

UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)

题目链接:uva 1252 题意: 有n个长度为m的二进制串,每个都是不同的. 为了把所有字符串区分开,你可以询问,每次可以问某位上是0还是1. 问最少提问次数,可以把所有字符串区分开来. 思路来源于:点击打开链接 思路: m很小,可以考虑状态压缩. dp[s1][s2]表示询问的状态为s1时,此时能猜到状态包含s2时最小需要的步数. 当询问的几位=s2的二进制串小于2时就能区分出来了,dp[s1][s2]=0: 不能区分则再询问一次,s1|=(1<<k),如果问某位为0,则s2不变,问某位为

Doing Homework---hdu1074(状态压缩&amp;&amp;记忆化搜索)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074 有n(n<=15)门课需要做作业,每门课所需时间是used_time以及每门课作业上交的最后期限是deadline,晚交一天扣一分,现在来安排最好的写作业计划,让最终的扣除分数最少:   由于n的取值范围不大所以我们可以枚举除所有的状态进行判断是否是最优的即可,状态数为2^n-1; 我们可以用状态压缩来表示出各种状态:二进制中的第i为为1代表第i门课已经完成了. #include <cstd

hdu 4628 Pieces(状态压缩+记忆化搜索)

Pieces Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1811    Accepted Submission(s): 932 Problem Description You heart broke into pieces.My string broke into pieces.But you will recover one

ACM学习历程—ZOJ3471 Most Powerful(dp &amp;&amp; 状态压缩 &amp;&amp; 记忆化搜索 &amp;&amp; 位运算)

Description Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These atoms have some properties. When two of these atoms collide, one of them disappears and a lot of power is produced. Researchers know the way