题目
解释
- DFS
- 为了防止方案的重复
- 需要用传入start来确保每进入一层,从start开始搜索,方案的排列形式单调递增
- DP
- 和整数划分的思想一致
- f[i][j]第一维i代表能量总数,第二维j代表分身数
- 方案可以分为两个集合:最小值为0的,最小值不为0的
- 如果最小值为0,则可以删去这个分身,只考虑f[i][j-1]
- 如果最小值不为0,则将方案里的每个数都减去1,这样就一一映射到了f[i-j][j]的情况
- 这样前后之间就关联可递推了
代码段
算法一DFS暴搜
//DFS题型
#include<iostream>
using namespace std;
const int N=20;
int f[N];
int m,n,ans;
void dfs(int u,int start,int v)
{
if(n==u)
{
if(v==0)
{
ans++;
}
return;
}
else
{
if(start>v)return;
for(int i=start;i<=v;i++)
{
f[u]=i;
dfs(u+1,i,v-i);
}
}
}
int main()
{
int t;cin>>t;
while(t--)
{
cin>>m>>n;
dfs(0,0,m);
cout<<ans<<endl;
ans=0;
}
}
算法二(整数划分DP)
#include<iostream>
using namespace std;
const int N=11;
int f[N][N];
int t,n,m;
int main()
{
cin>>t;
while(t--)
{
cin>>m>>n;
f[0][0]=1;
for(int i=0;i<=m;i++)
for(int j=1;j<=n;j++)
{
f[i][j]=f[i][j-1];
//先考虑最小数为0的,这样就相当于给前j-1个物分配能量
if(i>=j)f[i][j]+=f[i-j][j];
//再考虑最小数不为0的,这样我们将分配能量减一,一一映射到最小数为0的情形
}
cout<<f[m][n]<<endl;
}
}