洛谷题单指南-进阶搜索-P4799 [CEOI 2015] 世界冰球锦标赛 (Day2)

原题链接:https://www.luogu.com.cn/problem/P4799

题意解读:n件物品,每件物品都有价值,总预算m,任选物品使得不超过总预算,求有多少种选择方案。

解题思路:

每总物品只有选或者不选两种情况,最直接的方法就是使用DFS搜索。

1、搜索

由于n比较大,直接搜索所有方案复杂度为2^40,显然不可行,这里又想到了折半搜索大法。

先搜索前一半物品的挑选方案,每件物品只有选或者不选两种情况,将每种方案物品的总价值保存到数组a,再搜索后一半物品,将每种方案物品的总价值保存到数组b。

2、查找

对a、b进行排序,对于a中每一个价值a[i],在b中二分查找到一个位置j,j是使得a[i] + b[j] <= m的最后一个位置,答案累加j + 1(数组下标从0开始)。

最后输出答案即可。

100分代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
LL n, m;
LL v[45];
vector<LL> a, b;
LL ans;

//考虑第u个物品,最终到第end个物品,当前选择的物品价值为sum,每一种方案的价值记录在res
void dfs(LL u, LL end, LL sum, vector<LL> &res)
{
    if(u > end)
    {
        res.push_back(sum);
        return;
    }
    dfs(u + 1, end, sum, res); //不选第u个
    if(sum + v[u] <= m) dfs(u + 1, end, sum + v[u], res); //选第u个
}

//在b中找到最后一个使得x+b[j]<=m的位置j
int find(LL x)
{
    int l = 0, r = b.size() - 1;
    while(l < r)
    {
        LL mid = l + r + 1 >> 1;
        if(x + b[mid] <= m) l = mid;
        else r = mid - 1;
    }
    return l;
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> v[i];

    dfs(1, n / 2, 0, a);
    dfs(n / 2 + 1, n, 0, b);
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());

    for(int i = 0; i < a.size(); i++)
    {
        int j = find(a[i]); //在b中找到最后一个使得a[i]+b[j]<=m的位置
        ans += j + 1;
    }
    cout << ans;

    return 0;
}

 

posted @ 2025-02-26 15:14  hackerchef  阅读(44)  评论(0)    收藏  举报