标签:
题目链接:
http://acdream.info/problem?pid=1726
题意:
给定n 个数,和一个数看,判断k能否由其中的任意个数的和组成。
分析:
因为n最大为40,暴力枚举所有的情况 复杂度为 2^40 肯定TLE ,然后就想到了折半枚举
分成两半,先处理前n/2个数的组合的情况 ,把所得结果哈希一下,然后再枚举后一半
的所有情况,然后在哈希表里查找。时间复杂度为 O(2^(N/2));
代码如下:
#include <stdio.h> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define PB push_back #define MP make_pair #define REP(i,n) for(int i=0;i<(n);++i) #define FOR(i,l,h) for(int i=(l);i<=(h);++i) #define DWN(i,h,l) for(int i=(h);i>=(l);--i) #define CLR(vis) memset(vis,0,sizeof(vis)) #define MST(vis,pos) memset(vis,pos,sizeof(vis)) #define MAX3(a,b,c) max(a,max(b,c)) #define MAX4(a,b,c,d) max(max(a,b),max(c,d)) #define MIN3(a,b,c) min(a,min(b,c)) #define MIN4(a,b,c,d) min(min(a,b),min(c,d)) #define PI acos(-1.0) #define INF 1000000000 #define LINF 1000000000000000000LL #define eps 1e-8 #define LL long long using namespace std; const int MAXN=1<<20; const int HASH = 1000007; struct hashmap//建立哈希表 { LL a[MAXN]; int head[HASH],next[MAXN],size; void init(){//初始化 MST(head,-1); size=0; } bool find(LL val){//查找一个元素是否在哈希表内 int tmp = (val%HASH + HASH)%HASH; for(int i = head[tmp];i!=-1;i=next[i]) if(val==a[i]) return true; return false; } void add(LL val){//添加元素到哈希表中 int tmp =(val%HASH+HASH)%HASH; if(find(val)) return; a[size]=val; next[size]=head[tmp]; head[tmp]=size++; } }h1; int n,m,num[55]; int main() { while(~scanf("%d%d",&n,&m)) { h1.init(); REP(i,n) scanf("%d",num+i); int t=n/2; REP(i,1<<t){ LL sum=0; REP(j,t){ if(i&(1<<j)) sum+=num[j]; } if(sum>m) continue; h1.add(sum); } int tt=n-t; int flag=0; REP(i,1<<tt){ LL sum=0; REP(j,tt){ if(i&(1<<j)) sum+=num[t+j]; } if(sum>m)continue; if(h1.find(m-sum)){ flag=1; break; } } if(flag) printf("Yes\n"); else printf("No\n"); } return 0; }
ACDREAM 1726 A Math game(折半枚举+hash)
标签:
原文地址:http://blog.csdn.net/bigbigship/article/details/45618721