CF279D The Minimum Number of Variables

一、题目

题目描述

n n n个数 a i a_i ai,还有 m m m个容器,第一步把 a 1 a_1 a1赋值给某一个容器,然后每一步的赋值操作就是选两个容器的和赋值给一个容器(随便选,不要求容器不同,但求和容器必须有值),第 i i i步赋值操作的返回值必须等于 a i a_i ai(从 2 2 2开始算),求 m m m的最小值,没有这样的 m m m输出 − 1 -1 1

数据范围

n ≤ 23 n\leq 23 n23 1 ≤ a i ≤ 1 e 9 1\leq a_i\leq 1e9 1ai1e9

二、解法

这个数据范围很容易联想到状态压缩吧,我们设 d p [ s ] dp[s] dp[s]为我们把当前状态 a i a_i ai一定出现在容器里的为 1 1 1,不一定在容器里的为 0 0 0,那么最终需要状态为 d p [ 2 n ] dp[2^n] dp[2n],也就是 a n a_n an一定在容器里,初始化 d p [ 2 1 ] dp[2^1] dp[21] 1 1 1,一开始 a 1 a_1 a1一定在容器里(具体实现时需要从 0 0 0开始存)

考虑转移,我们现在需要凑出 i i i,那么我们枚举 i i i之前的两个数( i i i之后的不可能出现),这两个数的和为 i i i,然后我们把当前状态去掉 i i i这一位之后添加上枚举的两个数的位置继续搜索,得到返回值之后我们和当前状态的容器数(也就是 1 1 1的个数)取一个最大值然后更新答案即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 23;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,a[M],dp[1<<M];
int dfs(int x,int p)
{
    if(dp[x]) return dp[x];
    int c=__builtin_popcount(x),res=25;
    for(int i=0;i<p;i++)
        for(int j=0;j<=i;j++)
            if(a[i]+a[j]==a[p])
            {
                int t=dfs((x&~(1<<p))|(1<<p-1)|(1<<i)|(1<<j),p-1);
                res=min(res,max(t,c));
            }
    return dp[x]=res;
}
int main()
{
    n=read();
    for(int i=0;i<n;i++)
        a[i]=read();
    dp[1]=1;
    int t=dfs(1<<(n-1),n-1);
    if(t==25) puts("-1");
    else printf("%d\n",t);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值