送礼物(二分加双向DFS)

题目链接

题意:给你n个礼物重量,给你一个M力量,看你一次性搬动不超过M的礼物重量。

思路:看似背包,但M太大。所以要用DFS,但n也有45,所以考虑双向DFS先搜前半部分满足情况的所有重量,然后去重,再往后半部分搜索,并二分找答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#define ll long long
using namespace std;
const int maxn=(1<<24)+10;
ll n,m;
ll a[maxn],b[maxn];
ll k;
ll ans;
bool cmp(ll a,ll b)
{
    return a>b;
}
ll find(ll sum)
{
//    printf("m-sum: %lld\n",m-sum);
    int y=k;
    if(b[y]>m-sum)
        y=upper_bound(b+1,b+1+k,m-sum)-b-1;
   // printf("y:  %d\n",y);
    ans=max(ans,b[y]+sum);
}
int dfs(int x,ll sum)
{
    if(x==(n/2+2)+1)
    {
        b[++k]=sum;
        return 1;
    }
    dfs(x+1,sum);
    if(sum+a[x]<=m)
    dfs(x+1,sum+a[x]);
}
int dfs2(int x,ll sum)
{
    if(x==n+1)
    {
        find(sum);
        return 1;
    }
    dfs2(x+1,sum);
    if(sum+a[x]<=m)
    dfs2(x+1,sum+a[x]);
}
int main()
{
    scanf("%lld%lld",&m,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    sort(a+1,a+n+1,cmp);
    dfs(1,0);
    sort(b+1,b+k+1);
    k=unique(b+1,b+k+1)-(b+1);
    dfs2(n/2+3,0);
    printf("%lld\n",ans);
    
    
 } 

猜你喜欢

转载自www.cnblogs.com/2462478392Lee/p/11291391.html