• J


    J - 砝码称重

    Time Limit: 2000/1000 MS (Java/Others)      Memory Limit: 128000/64000 KB (Java/Others)
    Submit Status

    Problem Description

    有一个物品和一些已知质量的砝码和天平,问能不能用这些砝码称出这个物品的重量(天平两边都可以放砝码)

    Input

    多样例输入,样例数<=20000

    对于每个样例:

    第一行输入两个数n,m,表示砝码数量和重物质量,1 ≤ m ≤ 1018

    第二行输入n个数a1 ,a2 , ... ,an ,1018 ≥ ai+1 ≥ 3 * ai ≥ 1

    Output

    Case x: y

    x代表第几个样例,若能称出重物的质量,y为YES,否则y为NO

    Sample Input

    3 7
    1 3 9

    Sample Output

    Case 1: YES

    Hint

    样例为一边盘放重物和质量为3的砝码,另一边盘放质量为1和9的砝码
     
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int N=1e5+10;
     5 const int INF=0x3f3f3f3f;
     6 int cas=1,T;
     7 int n,vis[40];
     8 LL a[40],b[40],m;
     9 bool dfs(int x,LL sum,int v)
    10 {
    11     if(sum==0) return 1;
    12     if(x<0 || b[x]<sum || sum<0) return 0;
    13     if(!vis[x])
    14     {
    15         vis[x]=v;
    16         if(dfs(x-1,sum-a[x],v)) return 1;
    17         vis[x]=0;
    18     }
    19     if(dfs(x-1,sum,v)) return 1;
    20     return 0;
    21 }
    22 bool solve(LL sum,int v)
    23 {
    24     if(sum<0) return 0;
    25     int id=0;
    26     while(a[id]<=sum) id++;
    27     if(dfs(id-1,sum,v)) return 1;
    28     if(!vis[id-1])
    29     {
    30         vis[id-1]=v;
    31         if(solve(sum-a[id-1],v)) return 1;
    32         vis[id-1]=0;
    33     }
    34     if(!vis[id])
    35     {
    36         vis[id]=v;
    37         if(solve(a[id]-sum,v^1)) return 1;
    38         vis[id]=0;
    39     }
    40     return 0;
    41 }
    42 int main()
    43 {
    44 //    freopen("1.in","w",stdout);
    45     freopen("1.in","r",stdin);
    46     freopen("1.out","w",stdout);
    47 //    scanf("%d",&T);
    48     while(scanf("%d%lld",&n,&m)==2)
    49     {
    50         memset(vis,0,sizeof(vis));
    51         a[0]=b[0]=0;
    52         for(int i=1;i<=n;i++)
    53         {
    54             scanf("%lld",a+i);
    55             b[i]=b[i-1]+a[i];
    56         }
    57         a[n+1]=1LL*INF*INF;
    58         b[n+1]=b[n]+a[n+1];
    59         vis[0]=vis[n+1]=1;
    60         printf("Case %d: ",cas++);
    61         if(solve(m,2))
    62         {
    63             int sum1=0,sum2=0;
    64             puts("YES");
    65             /*for(int i=1;i<=n;i++) if(vis[i]==2) printf("%d ",a[i]),sum1+=a[i];
    66             printf("
    ");
    67             for(int i=1;i<=n;i++) if(vis[i]==3) printf("%d ",a[i]),sum2+=a[i];
    68             printf("
    ");
    69             printf("sum1:%d sum2:%d m:%d dif:%d
    ",sum1,sum2,w,sum1-sum2);*/
    70         }
    71         else puts("NO");
    72     }
    73 //    printf("%d %d
    ",clock(),CLOCKS_PER_SEC);
    74 //    printf("time=%.3f
    ",(double)clock()/CLOCKS_PER_SEC);
    75     return 0;
    76 }
    solve.cpp
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef unsigned long long ULL;
     4 typedef long long LL;
     5 const int INF = 0x3f3f3f3f;
     6 const double eps = 1e-9;
     7 long long a[40];
     8 int vis[40];
     9 int cas=1;
    10 int check(int n, LL x, LL p)
    11 {
    12     for(int i=n-1;i>=0;--i)
    13     {
    14         if(x - a[i] >= p) x -= a[i], vis[i] = 0;
    15         if(x >= p + a[i]) p += a[i], vis[i] = 2;
    16     }
    17     if(x == p) return 1;
    18     else return 0;
    19 }
    20  
    21 int main()
    22 {
    23 //    freopen("1.in","r",stdin);
    24 //    freopen("t1.out","w",stdout);
    25     int T, cas=1;
    26     int n;
    27     LL m;
    28     while(scanf("%d%lld", &n, &m) == 2)
    29     {
    30         for(int i=0;i<n;++i)
    31             scanf("%lld", &a[i]);
    32         sort(a, a+n);
    33         int flag = 0;
    34         long long sum = m;
    35         for(int i=0;i<n&&!flag;++i)
    36         {
    37             memset(vis, 0, sizeof vis);
    38             for(int j=0;j<i;++j) vis[j] = 1;
    39             vis[i] = 2;
    40             if(sum == a[i])
    41                 flag = 1;
    42             else
    43             {
    44                 flag = check(i, sum, a[i]);
    45                 if(!flag)
    46                 {
    47                     memset(vis, 0, sizeof vis);
    48                     for(int j=0;j<i;++j) vis[j] = 1;
    49                     flag = check(i, sum, 0);
    50                 }
    51                 sum += a[i];
    52             }
    53         }
    54         printf("Case %d: ",cas++);
    55         puts(flag?"YES":"NO");
    56 /*        if(flag)
    57         {
    58             LL sum = m;
    59             for(int i=0;i<n;++i) if(vis[i] == 1) printf("%lld ", a[i]), sum += a[i]; puts("");
    60             printf("lsum:%lld
    ", sum);
    61             sum = 0;
    62             for(int i=0;i<n;++i) if(vis[i] == 2) printf("%lld ", a[i]), sum += a[i]; puts("");
    63             printf("rsum:%lld
    ", sum);
    64         }*/
    65     }
    66      
    67 //    printf("time=%.3lf
    ",(double)clock()/CLOCKS_PER_SEC);
    68     return 0;
    69 }
    solve.cpp

    题解:

    由砝码质量的上限可知n只有几十。
    若a[i]刚好大于m,则不会用到a[i+1],
    因为a[1]+a[2]+...+a[i]+m < a[i+1]/2+m <= a[i+1]/2+a[i+1]/3 < a[i+1]
    递归执行以下过程
    1.每次搜索比m小的a[i]能否凑成m
    2.若不可以凑成,则m=a[i]-m,回到1
    3.若2还是不可以凑成,则m=m-a[i-1],回到1

    搜索能否凑成a[i]时记得剪枝

  • 相关阅读:
    MaaS系统概述
    流处理认识
    事务补偿
    Hystrix原理与实战
    RPC概念和框架
    git remote: error: hook declined to update
    Unity CombineTexture
    Windows Powershell统计代码行数
    unity面试题二
    unity面试题一
  • 原文地址:https://www.cnblogs.com/cdyboke/p/7010582.html
Copyright © 2020-2023  润新知