• BZOJ2679: [Usaco2012 Open]Balanced Cow Subsets


    n<=20个数,求能分成两个和相同的子集的子集数。

    枚举子集的子集,复杂度3^n,不可,考虑折半。在一种可行方案中,每个数的系数只会是0,-1,1,题目就是要求找和为0的两个子集拼起来,将其中一个子集取反就对应成两个值相同的方案。比如找到一个子集值为x,那么另一个子集的值应为-x,只要把-x这个子集的系数全部取反,就得到两个值相同的集合,对应一种方案。

    这样转换方便折半搜索的合并过程。在合并时,枚举左边的集合,把该集合对应的状态加进数组里排序,预先把右边所有状态排序后,就可以线性时间内比较相同。若是没有转换,则需要找和为0的两个状态,麻烦!复杂度6^(n/2)。

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<algorithm>
     5 //#include<iostream>
     6 using namespace std;
     7 
     8 int n,half;
     9 #define maxn 100011
    10 int first[maxn],list[maxn],next[maxn],cntl=0;
    11 struct Right
    12 {
    13     int v,S;
    14     bool operator < (const Right &b) const {return v<b.v;}
    15 }r[maxn];int cntr=0;
    16 bool vis[1100011];
    17 int a[23];
    18 int tmp[maxn],lt=0;
    19 void dfsl(int p,int v,int S)
    20 {
    21     if (p==half+1)
    22     {
    23         list[++cntl]=v;
    24         next[cntl]=first[S];
    25         first[S]=cntl;
    26         return;
    27     }
    28     dfsl(p+1,v,S);
    29     dfsl(p+1,v+a[p],S|(1<<(p-1)));
    30     dfsl(p+1,v-a[p],S|(1<<(p-1)));
    31 }
    32 void dfsr(int p,int v,int S)
    33 {
    34     if (p==n+1)
    35     {
    36         r[++cntr].v=v;
    37         r[cntr].S=S;
    38         return;
    39     }
    40     dfsr(p+1,v,S);
    41     dfsr(p+1,v+a[p],S|(1<<(p-1)));
    42     dfsr(p+1,v-a[p],S|(1<<(p-1)));
    43 }
    44 int main()
    45 {
    46     scanf("%d",&n);half=n/2;
    47     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    48     memset(first,0,sizeof(first));
    49     dfsl(1,0,0);dfsr(half+1,0,0);
    50     sort(r+1,r+1+cntr);
    51     memset(vis,0,sizeof(vis));
    52     for (int i=0;i<(1<<half);i++)
    53     {
    54         lt=0;
    55         for (int j=first[i];j;j=next[j]) tmp[++lt]=list[j];
    56         sort(tmp+1,tmp+1+lt);
    57         int k=1;
    58         for (int j=1;j<=cntr;j++)
    59         {
    60             while (k<=lt && tmp[k]<r[j].v) k++;
    61             if (k==lt+1) break;
    62             if (tmp[k]==r[j].v) vis[i|r[j].S]=1;
    63         }
    64     }
    65     int ans=0;
    66     for (int i=1;i<(1<<n);i++) if (vis[i]) ans++;
    67     printf("%d
    ",ans);
    68     return 0;
    69 }
    View Code

    注意不要把0算进去。。。。。。

  • 相关阅读:
    IIFE(立即执行函数表达式)
    函数劫持
    nuxt.js怎么写一个全局的自定义指令
    nuxtjs里面使用vuex
    Nuxt.js端口冲突 Nuxt.js 如何更改端口配置?
    nuxt怎么去新增页面
    nuxt服务端渲染怎么引入element ui
    mac安装vue-cli和nuxt
    正则-怎么把字符串里面的英文去掉
    mac如果将项目部署到github,以及 github部署静态网站
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7349171.html
Copyright © 2020-2023  润新知