原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4016
题意:从给出的N个数中,选出K个数进行与运算,求出最小值
一看到这题目,哎,就知道暴力是绝对超时的,可是之后,就没之后……………………
看了网上的思路,这剪枝太有技巧了,orz
思路如下:
1.从当前值开始,如果选上剩下的所有,也不能小于已得最优值的话,返回。
2.最优值不用等到累积选到k数才更新,而是不断更新,因为与运算结果比原来两个都小,所以这也是一个剪枝。
3.预处理,从小到大排序,可想而知,先选小的,得到的最优值更接近于结果,是个强剪枝,没有这个2900ms+,加上600ms+。
太强大了
原文的链接:http://hi.baidu.com/jiantaodongshe/blog/item/2b489b1c3d61bc04403417f7.html
代码:
#include<iostream> #include<algorithm> #define N 45 using namespace std; __int64 MAX=0x7fffffffffffffff; __int64 a[N],sum[N],ans; int k,n; void dfs(int t,int d,__int64 num) { if(ans>num) ans=num; if(t==n+1||d==k) return; __int64 s=num; s &= sum[t]; if(s>=ans)return;//思路中的2 dfs(t+1,d+1,num&a[t]); dfs(t+1,d,num); } int main() { int cas,T=0; cin>>cas; while(cas--) { scanf("%d %d",&n,&k); for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); sort(a+1,a+n+1); sum[n]=a[n]; for(int i=n-1;i>=1;i--) sum[i]=a[i]&sum[i+1]; ans=MAX; dfs(1,0,MAX); printf("Case #%d: ",++T); printf("%I64d\n",ans); } return 0; }