折半搜索

https://ac.nowcoder.com/acm/contest/889/D(超大背包)

#include<bits/stdc++.h>
using namespace std;
//__
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
struct node{
    int num;
    ull sum;
}a[1<<19],b[1<<19];
bool cmp(node p,node q){
    return p.sum<q.sum;
}

int main(){
    int n;
    ull s;
    scanf("%d%llu",&n,&s);
    int lena=1,lenb=1;
    int p=n/2;
    for(int i=0;i<p;i++){
        ull x;
        scanf("%llu",&x);
        int m=lena;
        for(int j=0;j<m;j++){
            a[lena].num=(a[j].num|(1<<i));
            a[lena].sum=a[j].sum+x;
            lena++;
        }
    }
    for(int i=p;i<n;i++){
        ull x;
        scanf("%llu",&x);
        int m=lenb;
        for(int j=0;j<m;j++){
            b[lenb].num=(b[j].num|(1<<i));
            b[lenb].sum=b[j].sum+x;
            lenb++;
        }
    }
    sort(a,a+lena,cmp);
    sort(b,b+lenb,cmp);
    int l=0,r=lenb-1;
    while(l<lena){
        while(a[l].sum+b[r].sum>s&&r)
            r--;
        if(a[l].sum+b[r].sum==s)
            break;
        l++;
    }
    for(int i=0;i<(int)n/2;i++)
        printf("%d",(a[l].num>>i)&1);
    for(int i=int(n/2);i<n;i++)
        printf("%d",(b[r].num>>i)&1);
    return 0;
}
View Code

 https://www.luogu.org/problem/SP11469

题意:在n个数中去若干个数,再把这若干个数分成俩个集合,使这俩个集合的sum相同,问方案数

分析:n<=20,要是要求全部能取还可以直接用2进制枚举,但他要取若干个,所以考虑把20对半折,直接搜索

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int M=2e6+5;
vector<int>vis[M];
map<ll,int>cmp;
ll yes[M];
int n,midd,cnt;
ll a[M];
void dfs1(int i,int sum,int nowsta){
    if(i>midd){
        if(!cmp[sum])
            cmp[sum]=++cnt;
        vis[cmp[sum]].pb(nowsta);
        return ;
    }
    dfs1(i+1,sum,nowsta);///不取这个数 
    dfs1(i+1,sum+a[i],nowsta|(1<<(i-1)));///把这个数取到第一个集合 
    dfs1(i+1,sum-a[i],nowsta|(1<<(i-1)));///把这个数取到另外的一个集合中 
}
void dfs2(int i,int sum,int nowsta){
    if(i>n){
        int x=cmp[sum];
        for(int i=0;i<vis[x].size();i++){
            yes[vis[x][i]|nowsta]=1;
        }
        return ;
    }
    dfs2(i+1,sum,nowsta);
    dfs2(i+1,sum+a[i],nowsta|(1<<(i-1)));
    dfs2(i+1,sum-a[i],nowsta|(1<<(i-1)));
}
int main(){
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    midd=n/2;
    dfs1(1,0,0);
    dfs2(midd+1,0,0);
    int ans=0;
    for(int i=1;i<(1<<n);i++)
        ans+=yes[i]; 
    printf("%d\n",ans);
    return 0;
}
View Code

 

 

posted @ 2019-08-15 19:40  starve_to_death  阅读(142)  评论(0编辑  收藏  举报