zoukankan      html  css  js  c++  java
  • P3067 [USACO12OPEN]平衡的奶牛群(折半暴搜)

    暴搜无疑....

    首先考虑纯暴搜......

    考虑每一个数:

    1. 选在左边集合
    2. 选在右边集合
    3. 不选

    一共三种情况,用一个数组记录搜到的答案,所以暴搜是3^N的复杂度...直接死亡

    于是讲折半暴搜....

    把区间分为两半,对每一半进行dfs,用两个数组(vector)分别记录答案,于是复杂度就是3^(n/2)*2,在n<=20的情况下,能接受。

    但是

    如果这么简单,那就不是老师找的紫题的风格了....

    存储了两个区间的数组,怎么统计答案呢?

    话说折半暴搜的难点就在于统计答案了吧.....

    对于每个半区间进行排序,然后的暴力?

    那不可能,超时不说,还会有重复的记录....

    重复是因为:同时可能有一个数存在于左右两个区间中....很尴尬....

    这里是这一题的关键,怎么去重。

    这里使用了状压的思想,对于每一个搜到底的状态,我们记录一个01串,看哪些数被使用过,然后在统计答案的时候使用vis判重。

    这个vis真的是太妙了!!!!

    把两个数的状态或起来,看有没有重复使用的状态

    (太神了

    if(!vis[a[l].id|b[r].id])
    {
        ans++;
        vis[a[l].id|b[r].id]=1;
    }

    于是,剩下的就是要在数组中寻找那个关键点pos了.

    因为排序后数组单调,所以找到这个pos之后,后面所有的答案都可能符合,只要去重就行了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=22;
    int n;
    int ans;
    int w[maxn<<1],vis[1<<maxn];
    struct node
    {
        int sum,id;
    };
    int cnta,cntb;
    node a[1<<maxn];
    node b[1<<maxn];
    int mid;
    void dfs1(int now,int sum,int id)
    {
        if(now==mid+1)
        {
            a[++cnta].sum=sum;
            a[cnta].id=id;
            return;
        }
        
        
        {
            dfs1(now+1,sum,id);
            dfs1(now+1,sum+w[now],id+(1<<(now-1)));
            dfs1(now+1,sum-w[now],id+(1<<(now-1)));
        }
    }
    void dfs2(int now,int sum,int id)
    {
        if(now==n+1)
        {
            b[++cntb].sum=sum;
            b[cntb].id=id;
            return;
        }
        
        {
            dfs2(now+1,sum,id);
            dfs2(now+1,sum+w[now],id+(1<<(now-1)));
            dfs2(now+1,sum-w[now],id+(1<<(now-1)));
        }
    }
    
    bool cmp1(node a,node b)
    {
        return a.sum<b.sum;
    }
    bool cmp2(node a,node b)
    {
        return a.sum>b.sum;
    }
    
    
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
        }
        mid=n>>1;
        dfs1(1,0,0);
        dfs2(mid+1,0,0);
        sort(a+1,a+cnta+1,cmp1);
        sort(b+1,b+cntb+1,cmp2);
        int l=1,r=1;
        while(l<=cnta&&r<=cntb)
        {
            while(r<=cntb&&-a[l].sum<b[r].sum)r++;
            int pos=r;
            while(r<=cntb&&-a[l].sum==b[r].sum)
            {
                if(!vis[a[l].id|b[r].id])
                {
                    ans++;
                    vis[a[l].id|b[r].id]=1;
                }
                r++;
            }
            if(l<cnta&&a[l].sum==a[l+1].sum)
            r=pos;
            l++;
        }
        printf("%d",ans-1);
        return 0;
    }

    (完)

  • 相关阅读:
    你是通过什么渠道获取一般人不知道的知识和信息的?
    用python写MapReduce函数——以WordCount为例
    准确率,召回率,F值,机器学习分类问题的评价指标
    【RS】AutoRec: Autoencoders Meet Collaborative Filtering
    2018 推荐系统总结
    关于协同过滤推荐系统札记
    【RS】Wide & Deep Learning for Recommender Systems
    NeuCF源码中用到的模块(函数)
    【RS】:论文《Neural Collaborative Filtering》的思路及模型框架
    Keras 使用过程问题汇总
  • 原文地址:https://www.cnblogs.com/ajmddzp/p/11582078.html
Copyright © 2011-2022 走看看