2022 年 7 月の上海コンピューター月例コンテストに向けた梱包に関する質問

梱包の問題

この質問は主に、ディープサーチプルーニングの能力を調べることです。

答え:

まず、このトピックを直接検索すると、ccという不確かな数字が見つかります。c 、その後、反復深化またはバイナリ回答を使用できます。ここでは、説明するためにバイナリ回答を使用します。

剪定:

  1. 現時点で答えが見つかった場合は、直接戻ってください。
  2. 現在の最大可能値が合計より小さい場合は、戻ります。
  3. i 番目のグループと i+1 番目のグループが同じスペースを持つ場合は続行します。
  4. (形而上学) 数字を大きいものから小さいものに並べ替える (数字の方が影響力が大きいため)

最後に dfs について説明します;
dfs(int step, int sum) はステップ数を示し、現在の最大値は sum です。

ACコード:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,l,r) for(int i=l;i<=r;i++)//宏定义
#define per(i,r,l) for(int i=r;i>=l;i--)
const int N = 50,INF=1e9,mod=INF+7;
int a[N],b[N];
int n,c,mid,cnt;
bool flag = false;

void dfs(int step,int sum){
    
    
	if(flag)return;//如果找到答案了
	if(sum < cnt) return;//如果当前最大值比所有数字加起来还小
	if(step > n){
    
    //满足了全部的数字
		flag = true;
		return;
	}
	rep(i,1,mid){
    
    //枚举当前a[step]数字放在哪一组
		if(b[i] + a[step] <= c){
    
    //不超过c
			b[i] += a[step];
			if(c-b[i] < a[n]) dfs(step+1,sum-c+b[i]);//如果这一组剩下的的空间小于最小的数,减去这些浪费的空间
			else dfs(step+1,sum);
			b[i] -= a[step];
		}
		while(b[i] == b[i+1])i++;//重复无需判断(没有此剪枝90分)
	}
}
bool cmp(int a,int b){
    
    return a>b;}
int main()
{
    
    
	int l=0,r,ans=INF;
	cin >> n >> c;
	rep(i,1,n){
    
    
		cin >>a[i];
		l += a[i];
		cnt += a[i];
	}
	sort(a+1,a+1+n,cmp);//从大到小排序,通常更快
	if(l % c == 0)l/=c;//至少需要ceil(l/c)组;
	else l = l/c+1;
	r = n;
	while(l <= r){
    
    //二分答案(迭代搜索也可以通过)
		mid = (l + r) >> 1;
		flag = 0;//初始化,下同
		fill(b,b+1+mid,0);//填充函数,将b至b+n填充为0
		dfs(1,mid*c);//mid*c 是指此时状态的最大可能满足多大的数字
		if(flag){
    
    
			r = mid-1;
			ans = min(ans,mid);
		}else l = mid+1;
	}
	cout << ans <<endl;
	return 0;
}

おすすめ

転載: blog.csdn.net/onlyfirer/article/details/126162170