首页 > 代码库 > lightoj 1235 Coin Change (IV)(折半枚举)

lightoj 1235 Coin Change (IV)(折半枚举)

  1.   话说这是俺们学校暑假集训完的一道题,刚看到以为是到水题,后来发现者复杂度也太大了,受不了了,比赛完也没搞出来,然后欣爷说这是折半枚举。然后就摸摸的学了一下,又把这道题写了一下,
  2. 所谓折半枚举就是先算出来一半,再算一半,然后用二分查找看看能不能搞到这一发状态,可以的话就是可以了,
  3. 题意:给你两个数n,k,下面再给你n个数,表示你现在有的硬币的面值,每种硬币面值的有两个,看是否可以支付k
  4. 题解思路:首先以为只有三种状态,直接dfs就好了,后来发现复杂度太大了,然后死了撸就是上面的,详细情残考代码
  5. 源代码:
    #include  <cstdio>
    #include  <cstring>
    #include  <algorithm>
    using namespace std;
    int a[28];
    long long  a1[20005],a2[20005];
    int s,e;
    int T;
    int t1,t2;
    int n,k;
    
    void dfs(int x,long long v) {
    
        if(x==e) {
            if(e==n) a1[t1++]=v;
            else if(e==n/2)  a2[t2++]=v;
            return ;
        }
    
        for(int i=0; i<=2; i++)
            dfs(x+1,v+i*a[x]);
    }
    
    int main() {
        while(scanf("%d",&T)==1) {
            int cases=1;
            while(T--) {
                memset(a1,0,sizeof(a1));
                memset(a2,0,sizeof(a2));
                scanf("%d%d",&n,&k);
                for(int i=0; i<n; i++)
                    scanf("%d",&a[i]);
                t1=t2=0;
                e=n/2;
                dfs(0,0);
                e=n;
                dfs(n/2,0);
                sort(a2,a2+t2);
                int j,l,mid,r;
                for( j=0; j<t1; j++) {
                    long long h=k-a1[j];
                    l=0;
                    r=t2-1;
                    while(l<=r) {
                        mid =(l+r)>>1;
                        if(a2[mid]==h)break;
                        if(a2[mid]>h) r=mid-1;
                        else l=mid+1;
                    }
                    if(l<=r) break;
                }
                if(j<t1)
                    printf("Case %d: Yes\n",cases++);
                else
                    printf("Case %d: No\n",cases++);
            }
        }
    }

lightoj 1235 Coin Change (IV)(折半枚举)