一千个人,就有一千个状态转移方程
方法一:
当成完全背包问题进行求解
f[i][j]=f[i-1][j]+f[i-1][j-i]+f[i-1][j-2*i]+.............
f[i][j-i]= f[i-1][j-i]+f[i-1][j-2*i]+...............
推出状态转移方程
f[i][j]=f[i-1][j]+f[i][j-i]
然后像完全背包一样转化为一维
f[j]=f[j]+f[j-i]
ac代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int n;
int f[N];
int main()
{
while (cin >> n)
{
memset(f, 0, sizeof(f));
f[0] = 1;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
f[j] = (f[j] + f[j - i]);
cout << f[n] << endl;
}
return 0;
}
方法二:
思路比较巧妙,看了y总讲解才想通还可以这么做
此时的f[i][j]中i和j分别表示
i:相加为i
j:一共分成了j个数相加
集合划分成两个
1.j个数中最小的数是1
2.j个数中最小的数大于1
很明显这两种划分不重不漏,涵盖了所有可能
然后就是状态转移方程
最小的数是1的,把1去掉 f[i-1][j-1]
最小的数大于1,对每个数减一 f[i-j][j]
所以推出
f[i][j]=f[i-1][j-1]+f[i-j][j]
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n;
int f[N][N];
int main()
{
while(cin>>n)
{
memset(f,0,sizeof(f));
f[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
f[i][j]=(f[i-1][j-1]+f[i-j][j]);
}
int ans=0;
for(int i=1;i<=n;i++)
ans+=f[n][i];
cout<<ans<<endl;
}
return 0;
}