现在的位置: 首页 > 综合 > 正文

ZOJ–3631–Watashi’s BG【枚举】

2018年01月12日 ⁄ 综合 ⁄ 共 2414字 ⁄ 字号 评论关闭

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4777

题意:有n天,告诉你每天的花费,别人给你一笔资金m,你自己也有一部分资金(可以假设花不完),每天只能花自己的钱或者花资金m中的钱,不能混着花,问m最多能花多少?

思路:考虑到数据比较小,n最多只有30,可以用枚举来做,枚举每天花m或者不花m,二进制枚举,复杂度2^30。这样复杂度要超时的,土豪说可以分两部分枚举,把结果存入两个数组,然后这两个数组结果再合并,复杂度n^2,这样二进制枚举最多是两个2^15,大大缩短了时间复杂度。

后来我又用dfs写了一遍,果断T,看了别人的代码,有个剪枝很关键,当前已使用的资金与所有还未使用的资金相加如果小于等于已得到的最大值,则剪枝。

二进制枚举代码

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 5000100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int a[200010],b[200010],va[40],vb[40];
int main(){
    int i,j;
    int n,m;
    int la,lb,cnta,cntb,ans;
    while(scanf("%d%d",&n,&m)!=EOF){
        la = lb = cnta = cntb = ans = 0;
        for(i=0;i<n/2;i++){
            scanf("%d",&va[i]);
            la++;
        }
        for(i=n/2;i<n;i++){
            scanf("%d",&vb[i-n/2]);
            lb++;
        }
        int l = (1<<la);
        for(i=0;i<l;i++){
            int sum = 0;
            for(j=0;j<la;j++){
                if(i&(1<<j)){
                    sum += va[j];
                }
            }
            if(sum<=m){
                a[cnta++] = sum;
                ans = max(sum,ans);
            }
        }
        l = (1<<lb);
        for(i=0;i<l;i++){
            int sum = 0;
            for(j=0;j<lb;j++){
                if(i&(1<<j)){
                    sum += vb[j];
                }
            }
            if(sum<=m){
                b[cntb++] = sum;
                ans = max(sum,ans);
            }
        }
        sort(a,a+cnta);
        sort(b,b+cntb);
        if(ans==m){
            printf("%d\n",ans);
            continue;
        }
        for(i=cnta-1;i>=0;i--){
            for(j=cntb-1;j>=0;j--){
                if(a[i]+b[j]<=m){
                    ans = max(ans,a[i]+b[j]);
                    break;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

DFS代码

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 5000100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int a[40],jz[40];
int n,m,maxm;
void dfs(int step,int cnt){
    if(cnt>m)   return ;
    maxm = max(maxm,cnt);
    if(step<1) return ;
    if(cnt+jz[step]<=maxm)  return ;    //防TLE剪枝
    dfs(step-1,cnt);
    dfs(step-1,cnt+a[step]);
}
int main(){
    int i,j;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        jz[0] = 0;
        for(i=1;i<=n;i++)    jz[i] = jz[i-1] + a[i];
        maxm = 0;
        dfs(n,0);
        printf("%d\n",maxm);
    }
    return 0;
}

抱歉!评论已关闭.