(1)思路:
x的范围不超过1e18,所以x最多只有19位数字。O(n2^n)状压枚举每位选或不选即可通过。(每个位置上两种状态0或1,多少位置,2的多少次方)还需要遍历n;
代码中有注释,可以先看一遍代码,方便理解
(2)测试数据
1234567
(3)代码(状压—状态压缩)
// 状压基本模板
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int zt[22]; //代表每一位上的数字,等下要跟状态相结合
int sum, ans;
ll num;
// ans 是原始的数,每位数字的总和
// sum 是后面染色的数字和
// 我们的判断依据就是,若sum * 2 == ans,说明染色的数字和==未染色数字和 (仔细想想,即染色数字和就是总和的一半)
int main () {
int j = 0;
cin >> num; //输入这个数字 123456
// 将每一位拆解开
while (num) {
zt[j++] = num % 10; // 从最低位开始,一个一个存进zt数组中( 倒着的) 654321
ans += num % 10; //再将每一位的数字求和
num /= 10; // 求下一位数字
}
// 最后得出的j,就知道有多少位了
// 枚举状态
// 1 << j 即二进制 左移 就是乘,右移即除,代表2^j个状态
for (int i = 0; i < 1 << j; ++i) {
int p = i; // 取出i(十进制)
sum = 0;
//转换成二进制(状态),并且与位置上的数字结合
// p % 2 就是从最低位开始,取二进制数 010101...
// k = 0,也是最低位
// 求和 1 代表染色,0代表不染色,染色就把和加上
for (int k = 0; k < j; ++k) {
sum += p % 2 * zt[k];
p /= 2; // 求下一位
}
if (sum * 2 == ans) {
cout << "Yes";
return 0;
}
}
cout << "No";
return 0;
}
- 对二进制处理的时候,&1,>> 1,位运算比 % /更快
// 状压基本模板
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int zt[22]; //代表每一位上的数字,等下要跟状态相结合
int sum, ans;
ll num;
// ans 是原始的数,每位数字的总和
// sum 是后面染色的数字和
// 我们的判断依据就是,若sum * 2 == ans,说明染色的数字和==未染色数字和 (仔细想想,即染色数字和就是总和的一半)
int main () {
int j = 0;
cin >> num; //输入这个数字 123456
// 将每一位拆解开
while (num) {
zt[j++] = num % 10; // 从最低位开始,一个一个存进zt数组中( 倒着的) 654321
ans += num % 10; //再将每一位的数字求和
num /= 10; // 求下一位数字
}
// 最后得出的j,就知道有多少位了
// 枚举状态
// 1 << j 即二进制 左移 就是乘,右移即除,代表2^j个状态
for (int i = 0; i < 1 << j; ++i) {
int p = i; // 取出i(十进制)
sum = 0;
//转换成二进制(状态),并且与位置上的数字结合
// p % 2 就是从最低位开始,取二进制数 010101...
// k = 0,也是最低位
// 求和 1 代表染色,0代表不染色,染色就把和加上
for (int k = 0; k < j; ++k) {
sum += (p & 1) * zt[k];
p = p >> 1; // 求下一位
}
if (sum * 2 == ans) {
cout << "Yes";
return 0;
}
}
cout << "No";
return 0;
}
(4)代码(DFS)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll sum;
ll x;
int getSum (ll x) {
int res = 0;
while (x) {
res += x % 10;
x /= 10;
}
return res;
}
int judge = 0; // 找到一个方案数,正好染色的数字之和等于总和的一半,就为true
//x 代表当前这个数字(后面几个已经选过了,还有哪些位置还没有选,
//tmp 代表选了后面几位,我会选到什么 (已经选到的数字的和)
void dfs(ll x, ll tmp) { //12345 取 13
if (x == 0 || tmp * 2 >= sum) {
if (tmp * 2 == sum) {
judge = 1;
}
return ;
}
// 当前x%10的数不取,直接到下一个数
dfs(x / 10, tmp);
// 当前x%10的数取
dfs(x / 10, tmp + x % 10);
}
int main () {
cin >> x; // 输入的数字
sum = getSum(x); // 求位置上的数字的和
dfs(x, 0);
if (judge) cout << "Yes";
else cout << "No";
return 0;
}