题意 : 给你6堆钻石,每一堆钻石的价值为 i 每一堆钻石有 i 个 问你能不能平分
题解 : 这种问题一般来说应该是dp… 当然这个也不例外。dp (i) 表示 能不能用这么多钻石表示出 i 这么多的价值 dp 的取值为 0 / 1 表示不可以和可以。这样的话我们就可以进行转移了
如果dp (i) = 1 的时候我们才进行转移 通过这种状态转移到后面的所有可能状态 dp (i + k * j) = 1; 这种转移 注意 :::当我们在转移的过程中发现如果有一个值已经被设置成1的时候,后面的一定已经都被设置成1了 (因为我们每次都是转移的一个相同的数);具体看代码吧 (注意转移的方向非常重要,是从大到小还是从小到大要考虑好)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 120005;
int dp[maxn] = {0};
int num[7] = {0};
int main () {
ios_base :: sync_with_stdio(false);
int cas = 1;
while (cin >> num[1] >> num[2] >> num[3] >> num[4] >> num[5] >> num[6]) {
if (!(num[1] + num[2] + num[3] + num[4] + num[5] + num[6])) break;
cout << "Collection #"<< cas ++ << ":" << endl;
memset (dp,0,sizeof(dp));
int sum = 0;
for (int i = 1;i <= 6; ++ i) {
sum += (i * num[i]);
}
if (sum % 2) {
cout << "Can't be divided." << endl;
cout << endl;
continue;
}
int u = sum / 2;
dp[0] = 1;
int mx = 0;
for (int i = 1;i <= num[1]; ++ i) dp[i] = 1;
mx = num[1];
for (int i = 2;i <= 6; ++ i) {
for (int j = mx;j >= 0;-- j) {
if (dp[j]) {
for (int k = 1;k <= num[i] && k * i + j <= u; ++ k) {
if (dp[j + k * i]) break;
dp[j + k * i] = 1;
}
}
}
mx = mx + num[i] * i;
}
if (dp[u]) {
cout << "Can be divided." << endl;
}
else {
cout << "Can't be divided." << endl;
}
cout << endl;
}
return 0;
}