题目:
输入
n=4 .
a={1,2,4,7}
k=13
输出
Yes (13 =2+4+7)
输入
n=4
a={1,2,4,7}
k=19
输出
No
分析:
递归状态搜索分析:
从a1开始按顺序决定每个数加或不加,在全部n个数都决定后再判断它们的和是不是k即可。因为状态数是2^(n+1),所以复杂度是0(2^n)。如何实现这个搜索,请参见下面的代码。注意a的下标与题目描述中的下标偏移了1。在程序中使用的是0起始的下标规则,题目描述中则是1开始的,这一点要注意避免搞混。
动态规划分析:
但是如果我们使用动态规划的话,时间复杂度将会是O(n*k)
不难得出当我们定义
dp[i+1][j]:=用前i种数字是否能够加和成j
为了用前i个数字加和成j,也就需要能用前i-1种数字加和成j或者是j-ai,由此可以得出递推关系式:
dp[i+1][j]=dp[i][j]+dp[i][j-ai],其中dp[0][0]=1;因为没有数并且和为零也就只有一种情况:不选
实现代码如下
#include<iostream>
#include<vector>
using namespace std;
vector<int>a(22);
int n,k;
void solve() {//动态规划
vector<vector<int>>dp(n+1,vector<int>(k+1,0));
dp[0][0]=1;
for(int i=0; i<n; ++i)
for(int j=0; j<=k; ++j)
dp[i+1][j]+=dp[i][j]+(j>=a [i]?dp[i][j-a[i]]:0);
if(dp[n][k])
cout<<"Yes";
else cout<<"No";
}
bool dfs(int i,int sum) {//dfs状态遍历
if(i==n)
return sum==k;
if(dfs(i+1,sum))
return true;
if(dfs(i+1,sum+a[i]))
return true;
return false;
}
int main() {
cin>>n;
for(int i=0; i<n; ++i)
cin>>a[i];
cin>>k;
//solve();
cout<<(dfs(0,0)?"Yes":"No");
return 0;
}