51Nod3049 挑选数字

Problem

给出n个正整数,从中挑选若干个,使得他们的和为m。如果存在多个,输出排序后字典序最小的一组。如果没有找到任何一组,输出"No Solution"。

Solution

如果n大于15,从16开始分成两部分,先枚举后一半可能出现的值,map记录,然后按顺序枚举前一半,如果能和某个值组成m就记录每个数,返回,再枚举后一半,找到具体的数字。

主要是dfs写的太烂了,交对看别人的才知道怎么写。

Code

#include<stdio.h>
#include<set>
#include<iostream>
#include<stack>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
typedef long long ll;
typedef long double ld;
typedef double db;
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int mod=1e9+7;
inline int mo(ll a,int p){
    return a>=p?a%p:a;
}
inline int rd() {
    int x = 0, f = 1;
    char ch;
    while (ch < '0' || ch > '9') {
        if (ch == '-')f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return f * x;
}
inline ll gcd(ll x, ll y){
    return y==0?x:gcd(y,x%y);
}
inline ll speed(ll a,ll b){
    ll cur=a,anss=1;
    while(b){
        if(b&1) anss=anss*cur;
        cur=cur*cur;
        b>>=1;
    }
    return anss;
}
const int MAXN=1e5;
bool ipr[MAXN+20];
int cnt,pri[MAXN/5];
void prime(){//埃式筛法
    int N=sqrt(MAXN)+0.5,mul;
    memset(ipr,true,sizeof(ipr));
    ipr[1]=false;
    for(int i=2;i<=N;i++){
        if(ipr[i]==true){
            i==2?mul=1:mul=2;
            for(int j=i*i;j<=MAXN;j+=i*mul){
                ipr[j]=false;
            }
        }
    }
    for(int i=2;i<=MAXN;i++){
        if(ipr[i]==true){
            pri[++cnt]=i;
        }
    }
}
int n,m;
int a[50];
int ans[50],ct=0,al=0,mid;
bool fg=false;
map<int,int>mp;
int sss=15;
void dfs(int cur,int sum,int cou){
    if(fg) return;
    if(sum==m){
        fg=true;
        ct=cou;
        return;
    }
    if(cur==n+1) return;
    ans[cou+1]=a[cur];
    if(sum+a[cur]<=m&&al-sum-a[cur]>=m-sum-a[cur]) dfs(cur+1,sum+a[cur],cou+1);

    if(al-sum>=m-sum) dfs(cur+1,sum,cou);

}
void dfs1(int cur,int sum){
    mp[sum]=1;
    if(cur==n+1) return;
    dfs1(cur+1,sum+a[cur]);
    dfs1(cur+1,sum);
}
void dfs2(int cur,int sum,int cou){
    if(fg) return;
    if(mp[m-sum]){
        fg=true;
        mid=sum;
        ct=cou;
        return;
    }
    if(cur==sss+1) return;
    ans[cou+1]=a[cur];
    if(sum+a[cur]<=m&&al-sum-a[cur]>=m-sum-a[cur]) dfs2(cur+1,sum+a[cur],cou+1);

    if(al-sum>=m-sum) dfs2(cur+1,sum,cou);

}
bool fg2=false;
void dfs3(int cur,int sum,int cou){
    if(fg2) return;
    if(sum==m){
        fg2=true;
        ct=cou;
        return;
    }
    if(cur==n+1) return;
    ans[cou+1]=a[cur];
    if(sum+a[cur]<=m&&al-sum-a[cur]>=m-sum-a[cur]) dfs3(cur+1,sum+a[cur],cou+1);
    if(al-sum>=m-sum) dfs3(cur+1,sum,cou);

}
int main(){
    //io_opt;

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        al+=a[i];
    }
    if(al<m){
        printf("No Solution
");
        return 0;
    }
    sort(a+1,a+1+n);
    if(n<=sss){
        dfs(1,0,0);
    }
    else{
        dfs1(sss+1,0);
        dfs2(1,0,0);
        //cout<<ct<<endl;
        if(fg) dfs3(sss+1,mid,ct);
        //cout<<ct<<endl;
    }


    if(fg){
        for(int i=1;i<=ct;i++){
            printf("%d ",ans[i]);
        }
        printf("
");
    }
    else{
        printf("No Solution
");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/sz-wcc/p/13188013.html