划分大理石_题解

原题链接

简明题意:

有价值分别为 1~6 的大理石各 a[1],a[2]...a[6] 块,现要将它们分成两部分,使得两部分价值之和相等,问是否可以实现,即两部分均为一半。
其中大理石的总数不超过 20000。
多组输入,并且只需判断能否实现目标。

思路:

本题由 硬币(Coins)的二进制方法衍生过来,这里一起讲解
由奇偶数不难看出,当石头总价值 sum 为偶数时,才符合题意;显然本题是多重背包且物品种类已知;本题建议用二进制优化较为合适;另外,我们 f[i] 数组的含义是:恰好部分A的价值为 i ,且用 bool 即可,这是从题意出发所确定的;我们把石头分为两部分,A和B,显然,当部分A价值=部分B时,部分A和部分B的价值为总价值一半,若能组合出总价值的一半,即 f[sum/2]=true ,那么就符合题意,反之不符题意。

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int s[10];
bool f[N];
vector<int> str;
int main(){
	while(cin >> s[1] >> s[2] >> s[3] >> s[4] >> s[5] >> s[6]){
		if(!s[1] && !s[2] && !s[3] && !s[4] && !s[5] && !s[6]) 
                        break;
		int sum = 0;
		str.clear();
		memset(f, 0, sizeof(f));
		for(int i = 1; i <= 6; i++){
			sum += s[i] *i;
			for(int p = 1; p <= s[i]; p *= 2){
				s[i] -= p;
				str.push_back(i * p);
			}
			if(s[i]) str.push_back(i * s[i]);
		}
		f[0] = true;
		for(auto t : str)
			for(int i = sum/2; i >= t; i--)
				f[i] |= f[i-t];
		if(f[sum / 2] && sum % 2 == 0) cout << "Can" << endl;
		else cout << "Can't" << endl;
	}
	return 0;
}
posted @ 2022-06-21 21:53  P32sx  阅读(60)  评论(1)    收藏  举报