洛谷T24242 购物券 dfs+hash

洛谷T24242 购物券

大意

多组测试数据,给定一个数m,给定一个长度为n的序列,问有没有子序列的和为m,有的话输出YES,没有输出NO

数据范围

对于40%的数据,
组数 1<=k<=5,1<=n<=25,1<=m<=100000,1<=a[i]<=50000; 1 <= k <= 5 , 1 <= n <= 25 , 1 <= m <= 100000 , 1 <= a [ i ] <= 50000 ;

对于100%的数据,
组数 1<=k<=10,1<=n<=40,1<=m<=2311,1<=a[i]<=1000000; 1 <= k <= 10 , 1 <= n <= 40 , 1 <= m <= 2 31 − 1 , 1 <= a [ i ] <= 1000000 ;

思路

数据不弱不强,直接深搜肯定超时,所以要剪枝。
因为是不要去数量的,所以可以直接开个hash表来剪枝。

代码

#include
#include
#define p 100003
#define hash(x) x%p
using namespace std;int a[41],m,n,h[p];bool v[41];//判断是否选过
int find(int x)//查找位置
{
    int y=hash(x);
    while(h[y]&&h[y]!=x) y=hash(++y);
    return y;
}
void init(int x)//放入哈希表
{
    h[find(x)]=x;
}
bool zd(int x)//判断
{
    return h[find(x)]==x;
}
void dfs(int dep,int sum)//深搜
{
    if((zd(sum)||sum>m||dep>n)&&sum) return;
    init(sum);//放入哈希表
    if(sum==m) //已经找到
     {
        v[0]=true;//标记
         puts("YES");//输出
        return;
     }
    for(int i=1;i<=n;i++)
     if(!v[i])
     {
        v[i]=true;
        dfs(dep+1,sum+a[i]);//继续搜
        v[i]=false;//回溯
     }
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)//一直做
    {
        fill(h,h+p,0);fill(v,v+40,0);//初始化
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);//输入
        sort(a+1,a+1+n);//排序,其实也没什么用
        dfs(1,0);//深搜
        if(!v[0]) puts("NO");//输出
    } 
}

你可能感兴趣的:(HASH,dfs)