双向DFS + 二分、满足限制条件下的最大化以及最小化问题

双向DFS

会给出某种物品数量大概在30~40之间,询问挑选出来的物品价值或体积,他们的和满足一定的限制,需要你求出最佳价值(不小于某一个数里最小的、不大于某一个数中最大的)。

Q1

题目链接:https://www.acwing.com/problem/content/4703/

C++代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 35;

int n, m, k;
int w[N];
int nums[1 << 16], cnt;
int res = 1e6;

void dfs_1(int u, int s)
{
    if(u == k)
    {
        nums[cnt ++] = s;
        return ;
    }
    
    dfs_1(u + 1, s + w[u]);
    dfs_1(u + 1, s);
}

void dfs_2(int u, int s)
{
    if(u >= n)
    {
        int l = 0, r = cnt - 1;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(nums[mid] + s >= m) r = mid;
            else l = mid + 1;
        }
        if(nums[r] + s >= m) res = min(res, nums[r] + s);
        return ;
    }
    
    dfs_2(u + 1, s + w[u]);
    dfs_2(u + 1, s);
}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n; i ++) cin >> w[i];
    sort(w, w + n);
    reverse(w, w + n);
    
    k = n / 2 + 1;
    dfs_1(0, 0);
    
    sort(nums, nums + cnt);
    cnt = unique(nums, nums + cnt) - nums;
    
    dfs_2(k, 0);
    
    cout << res << endl;
    return 0;
}

Q2

原题链接:https://www.acwing.com/problem/content/173/

C++代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 50;

int n, m, k;
int g[N];
int w[1 << 24], cnt;
int res;

void dfs_1(int u, int s)
{
    if(u >= k)
    {
        w[cnt ++] = s;
        return;
    }

    if(g[u] + 0ll + s <= m) dfs_1(u + 1, g[u] + s);
    dfs_1(u + 1, s);
}

void dfs_2(int u, int s)
{
    if(u >= n)
    {
        int l = 0, r = cnt - 1;
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(w[mid] + 0ll + s <= m) l = mid;
            else r = mid - 1;
        }

        if(w[r] + s <= m) res = max(res, w[r] + s);
        return;
    }

    if(s + 0ll + g[u] <= m) dfs_2(u + 1, s + g[u]);
    dfs_2(u + 1, s);
}

int main()
{
    scanf("%d%d", &m, &n);
    long long s = 0;
    for(int i = 0; i < n; i ++)
    {
        scanf("%d", &g[i]);
        s += g[i];
    }
    
    if(s <= m)
    {
        printf("%d\n", s);
        return 0;
    }

    sort(g, g + n);
    reverse(g, g + n);

    k = n / 2 + 1;
    dfs_1(0, 0);

    sort(w, w + cnt);
    cnt = unique(w, w + cnt) - w;

    dfs_2(k, 0);
    printf("%d\n", res);

    return 0;
}

注:Q1还可以使用DP来写,Q2只能使用双向DFS + 二分来写。

posted @ 2023-01-13 14:39  openallzzz  阅读(9)  评论(0编辑  收藏  举报  来源