描述
题解
N
比较小,深度优先搜索即可。
也可以使用动态规划,典型的0-1背包问题,可是K
太大,正常情况会挂,然而这道题数据比较弱,K
根本不到1e9
的量级。
所以如果K
的数据稍微一强,就会挂,可以优化超大背包,二进制枚举N/2
个状态,然后筛选出所有可能存在的状态,最后再二进制枚举剩下的N-N/2
个状态。(只是动态规划的思想,实际解题代码已经不像动态规划了)……
代码
One:
// 深度优先搜索解法
#include <iostream>
#include <cstdio>
const int MAXN = 22;
int N, K;
int A[MAXN];
bool dfs(int rest, int dep)
{
if (dep == N)
{
return false;
}
if (rest == A[dep])
{
return true;
}
if (rest > A[dep])
{
rest -= A[dep];
if (dfs(rest, dep + 1))
{
return true;
}
rest += A[dep];
}
return dfs(rest, dep + 1);
}
int main()
{
scanf("%d %d", &N, &K);
for (int i = 0; i < N; i++)
{
scanf("%d", A + i);
}
if (dfs(K, 0))
{
printf("Yes\n");
}
else
{
printf("No\n");
}
return 0;
}
Two:
// 弱数据动态规划解法
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAXN = 25;
const int MAXK = 10;
int A[MAXN];
int dp[MAXN][MAXK] = {0};
int main(int argc, const char * argv[])
{
int N, K;
cin >> N >> K;
for (int i = 1; i <= N; i++)
{
scanf("%d", A + i);
}
for (int i = 0; i <= N; i++)
{
dp[i][0] = 1;
}
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= K; j++)
{
if (j < A[i])
{
dp[i][j] = dp[i - 1][j];
}
else
{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - A[i]]);
}
}
}
if (dp[N][K])
{
cout << "Yes\n";
}
else
{
cout << "No\n";
}
return 0;
}
Three:
// 强数据超大背包优化
// 个人感觉已经有些不像动态规划了~\(≧▽≦)/~
#include <iostream>
#include <map>
using namespace std;
const int INF = 0x3f3f3f3f;
int n, k, d[25];
map<int, int> v;
void solve()
{
int n_1 = n / 2;
v.clear();
for (int i = 0; i < (1 << n_1); i++) // 1 << n_1: 每个数字都有选与不选两个状态
{ // n_1个数字则有2^n_1个状态组合,即1 << n_1
int sw = 0;
for (int j = 0; j < n_1; j++)
{
if (i & (1 << j))
{
sw += d[j];
}
}
v[sw] = 1;
}
int n_2 = n - n_1;
bool ok = 0;
for (int i = 0; i < (1 << n_2); i++)
{
int sw = 0;
for (int j = 0; j < n_2; j++)
{
if(i & (1 << j))
{
sw += d[j + n_1];
}
}
if (v[k - sw] == 1)
{
ok = 1;
break;
}
}
if (ok)
{
puts("Yes");
}
else
{
puts("No");
}
}
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++)
{
cin >> d[i];
}
solve();
return 0;
}