• POJ3977 Subset


    传送门

    题目大意:给定一个含有n个元素的集合,求出其中一个子集,使得在子集内所有元素的和的绝对值最小的情况下,子集元素个数最小。输出最小值和最少元素个数。n <= 35.

    这个题是很显然的折半搜索,我们先搜前一半,再搜后一半,搜到后一半的时候,我们在前一半元素之中二分去找最接近0的那一个值来更新答案。

    思路很清晰但是坑特别多……

    首先是,如果你采用我这种算法,你需要特判掉输入中有0的情况。否则的话会出现一些奇怪的问题……

    还有就是需要判重。因为我们是二分一个值之后还要找其前驱后继。后继没问题,但是如果有多个前驱的值是一样的而选取的元素不一样,那么是不行的,因为我们会取到元素最多的那一个。方法就是在sort之后判重,只取值相同的那些中元素最少的一个。

    还有就是,我们在搜前一半的时候需要更新答案。(这个忘了让我调了好久……)

    本题拍了几千组数据也没问题……但是想不到在这翻车。

    mrclr的代码有误都能过orzzzzzz

    之后看一下代码吧……与二进制相比唯一优秀的可能是比较清真。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define fr friend inline
    #define y1 poj
    
    using namespace std;
    typedef long long ll;
    const int M = 1000005;
    const ll INF = 1e18;
    const double eps = 1e-7;
    
    #define pr pair<ll,int>
    #define mp make_pair
    #define fi first
    #define sc second
    
    ll read()
    {
        ll ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    ll n,a[105],cnt,ans,minn,k,tot;
    pr num[M],res[M];
    
    ll Abs(ll x)
    {
       return x > 0 ? x : -x;
    }
    
    bool cmp(pr p, pr q)
    {
       if(p.fi == q.fi) return p.sc < q.sc;
       return p.fi < q.fi;
    }
    
    void dfs(int step,ll sum,ll take)
    {
       if(step > k)
       {
          if(take != 0)
          {
         ll f = Abs(sum);
         if(f < minn || (f == minn && take < ans)) minn = f,ans = take;
          }
          num[++cnt].fi = sum,num[cnt].sc = take;
          return;
       }
       dfs(step+1,sum,take),dfs(step+1,sum+a[step],take+1);
    }
    
    void judge(int p,ll c,ll t)
    {
       if(p > tot || p < 1) return;
       ll cur = Abs(res[p].fi + c),now = res[p].sc + t;
       if(!now) return;
       if(cur < minn || (cur == minn && now < ans)) minn = cur,ans = now;
    }
    
    void dfs2(int step,ll sum,ll take)
    {
       if(step == k)
       {
          int g = lower_bound(res+1,res+1+tot,mp(-sum,0),cmp) - res;
          judge(g,sum,take),judge(g+1,sum,take),judge(g-1,sum,take);
          return;
       }
       dfs2(step-1,sum,take),dfs2(step-1,sum+a[step],take+1);
    }
    
    int main()
    {
       while(1)
       {
          n = read(),k = n >> 1;if(!n) break;
          memset(num,0,sizeof(num));
          memset(res,0,sizeof(res));
          memset(a,0,sizeof(a));
          bool flag = 0;
          rep(i,1,n)
          {
         a[i] = read();
         if(a[i] == 0) flag = 1;
          }
          if(flag) {printf("0 1
    ");continue;}
          minn = INF,ans = a[0],cnt = tot = 0;
          dfs(1,0,0),sort(num+1,num+1+cnt,cmp);
          res[++tot] = num[1];
          rep(i,2,cnt) if(num[i].fi != num[i-1].fi) res[++tot] = num[i];
          dfs2(n,0,0);
          printf("%lld %lld
    ",minn,ans);
       }
       return 0;
    }
    View Code
  • 相关阅读:
    USACO--2.1The Castle
    浅谈python字符串存储形式
    面向对象——一起来复习托付与事件!
    数据结构——算法之(032)(求两个串中的第一个最长子串)
    读《浪潮之巅》有感
    关于android 怎样安装 assets文件下的apk
    每日一小练——求质数
    怎样使破解网页的禁止复制黏贴
    Angularjs Nodejs Grunt 一个样例
    《TCP/IP具体解释卷2:实现》笔记--域和协议
  • 原文地址:https://www.cnblogs.com/captain1/p/10073742.html
Copyright © 2020-2023  润新知