题目概述:
AC代码:
#include<iostream>
#define maxn 101
#define maxm 10001
using namespace std;
int ans;
int a[maxn];
int n,m;
int dp[maxn][maxm];
int main()
{
std::ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;++i)
cin>>a[i];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(j==a[i])
dp[i][j]=dp[i-1][j]+1;
else if(j>a[i])
dp[i][j]=dp[i-1][j]+dp[i-1][j-a[i]];
else
dp[i][j]=dp[i-1][j];
}
cout<<dp[n][m]<<endl;
return 0;
}
分析思路:
1.题目的意思解析一下,其实就是给一串数字序列,问从中选出若干数字使他们的和为m的方法数量。
2.这个题目很熟悉,部分和问题我之前用深搜做过,所以这题第一次我写的是dfs:
#include<iostream>
#define maxn 101
#define maxm 10001
using namespace std;
int ans;
int a[maxn];
int n,m;
int dp[maxn][maxm];//记忆化搜索
void dfs(int i,int sum)
{
if(dp[i][sum])
{
if(dp[i][sum])
dfs()
}
if(i==n)
{
if(sum==m)
++ans;
return;
}
if(sum>m)
return;
if(sum==m)
{
++ans;
return;
}
dfs(i+1,sum);
dfs(i+1,sum+a[i+1]);
}
int main()
{
std::ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;++i)
cin>>a[i];
dfs(0,0);
cout<<ans<<endl;
return 0;
}
剪枝了一次,在dfs里头加入了判断,如果和已经超过了m,那么怎么操作都不能和为m了。
数据规模很小,以为剪枝这一次肯定能ac,没想到最后一组数据有点变态,还是TLE了最后一发。
贴上洛谷这题最后一个测试点:
in:
36 32
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 4 8 16
out:
2147483647
有大量的1数据,导致递归计算次数很大。只好转向动态规划.
2.动态规划做法,定义dp[i][j]为到第i个数时能加成j的方法数量,那么根据j与a[i]的大小关系,做出不同的递推选择即可。可以看出递推对于大量的1数据是不怕的,因为每次递推也就是计算一次的事情。动态规划能成功ac这题。