题目描述
T组数据,n个数,m为目标数,判断这n个数中任意几个数之和能否等于m
题目解析
看到数据规模(231)没法用背包
我们考虑所有的状态,一共240种,也会超时
所以只需要暴力枚举前一半数存到哈希表中,上限220;再枚举后一半数,查找满足目标数的另一半,上限也是220
用dfs枚举所有数,到达上限时插入或查找
代码
#include<bits/stdc++.h>
#define p 4000043//质数
#define h(x) x%p
using namespace std;
int n,m,mid;
int a[p],x[50];
bool flag;
int read()
{
int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}//快读
int loc(int x)
{
int k=h(x);
while(a[k]!=0&&a[k]!=x)
k=h(++k);
return k;
}//查找关键字在哈希表的位置
void dfs1(int lev,int sum)
{
if(sum==m)
{
flag=1;//前一半就找到满足目标数的数
return;
}
if(lev>mid)
{
a[loc(sum)]=sum;//存进哈希表
return;
}
if(sum+x[lev]<=m) dfs1(lev+1,sum+x[lev]);//不超过上限就加
dfs1(lev+1,sum);
}//枚举前一半数的状态
void dfs2(int lev,int sum)
{
if(flag) return;
if(sum==m)
{
flag=1;//后一半就找到满足目标数的数
return;
}
if(lev>n)
{
if(a[loc(m-sum)]==m-sum)// 判断目标数-后一半数是否在哈希表里
flag=1;
return;
}
if(sum+x[lev]<=m) dfs2(lev+1,sum+x[lev]);//不超过上限就加
dfs2(lev+1,sum);
}//枚举后一半数的状态
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)//一直做
{
mid=n/2;
flag=0;
memset(a,0,sizeof(a));//初始化
for(int i=1;i<=n;i++) x[i]=read();//输入
dfs1(1,0);//深搜
if(!flag)
dfs2(mid+1,0);
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}