Balance Scale

好久没写博客了,这段时间感觉比较懒了,今天一时兴起想写一下博客,做个题吧。。

题意:给你n个物品,重量分别为a[i],再给你m个砝码,让你称重,是否能把这n个物品都能称出来

         (1)如果能 ,输出0

         (2)如果不能,那找一个任意重量的砝码,看是否能称出来,如果能称出来那就输出这个砝码的重量,如果有多个答案,输出最小的那个;

         (3)如果加一个砝码不能满足,输出-1。

思路:才开始的时候我用set存所有砝码任意组合的情况,然后遍历n个物品,复杂度为n*pow(3,m) ,果断超时,并且各种爆内存

比赛时各种自闭,嘤嘤嘤。后来才想到枚举各种情况时可以缩小砝码的范围,就是到第i个时,取1~(i-1)的交集,然后与第i个比较,再取交集,一直取到n,set中的第一个元素就是答案。。。

//#pragma GCC optimize (2)
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<math.h>
#include<time.h>
#include<vector>
#include<set>
#include<map>
#include <assert.h>
#include<stack>
#define LL  long long
#define mem(a,b) memset(a,b,sizeof(a))
using  namespace std;
const LL mod=1e9+7;
const double PI=acos(-1.0);
const LL INF=1e18;
const double eps=1e-10;
void quickread(){std::ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);}
int lowbit(int x){return x&(-x);}
int f[100005];
int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
int gcd (int a,int b){return b==0?a:gcd(b,a%b);}
int a[120];
int b[120];
int ans;
int cnt=0;
set<int>vis;
set<int>vis2;
int n,m;
int vis3[120];
void dfs(int x,int sum)
{
    if(x>=m+1)
    {
        int absum=abs(sum);
        if(vis.find(absum)==vis.end())
             vis.insert(absum);
        return ;
    }
    dfs(x+1,sum);
    dfs(x+1,sum-b[x]);
    dfs(x+1,sum+b[x]);
    return ;
}

int main()
{
     while(~scanf("%d%d",&n,&m)&&n&&m)
     {
         vis.clear();
         cnt=0;
         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
         for(int j=1;j<=m;j++) scanf("%d",&b[j]);
         dfs(1,0);

         int n1=n;
         mem(vis3,0);
         for(int i=1;i<=n;i++)
         {
             if(vis.find(a[i])!=vis.end())
                 vis3[i]=1,n1--;
         }
         if(n1==0)
         {
             printf("0\n");
             continue;
         }
         vis2.clear();
         int cnt=0;
         for(int j=1;j<=n;j++)
         {

             if(vis3[j]) continue;
             cnt++;
             set<int>vis4;
             if(cnt==1)
             {
                 vis4.clear();
                 for(auto it=vis.begin();it!=vis.end();it++)
                 {
                      int x=abs(a[j]-*it);
                      int y=abs(a[j]+*it);
                      if(vis4.find(x)==vis4.end())
                      {
                         vis4.insert(x);
                      }
                      if(vis4.find(y)==vis4.end())
                      {
                         vis4.insert(y);
                      }
                 }
                 vis2.clear();
                 vis2=vis4;
                 continue;
             }
             for(auto it=vis2.begin();it!=vis2.end();it++)
             {
                 int x=abs(a[j]-*it);
                 int y=abs(a[j]+*it);
                 if(vis4.find(x)==vis4.end()&&vis.find(x)!=vis.end())
                 {
                     vis4.insert(*it);
                 }
                 if(vis4.find(y)==vis4.end()&&vis.find(y)!=vis.end())
                 {
                     vis4.insert(*it);
                 }
             }
             vis2.clear();
             vis2=vis4;
         }
         if(!vis2.empty()) printf("%d\n",*vis2.begin());
         else printf("-1\n");
     }
     return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值