1664 | Accepted | 220K | 0MS | C++ | 1766B |
1664 | Accepted | 232K | 16MS | C++ | 1175B |
DP的做法是看discuss中有人提到的,非常巧妙。即对于任意的M和N,有两种情况:1.第一个盘子放一个苹果,那么N个盘子都得放一个苹果,即等同于DP[M - N][N];2.如果第一个盘子不放苹果,那么只用考虑后面 N-1个盘子就好,即等同于DP[M][N-1]。所以,我们有递推表达式:DP[M][N] = DP[M - N][N] + DP[M][N - 1].
DFS的做法是用3个量表示一个状态:m:当前要放的苹果的数目;last:上次(即后面那个盘子)放的苹果数目,当前要放的苹果数目不能大于last,另外当前要放的苹果数目不能少于m/n,这是因为要保证如果前面的所有盘子都和当前放的一样多时能够把m个苹果都放下了;n:当前正在放的盘子编号,这里用的是DFS从后往前放,即从盘子的编号N到1。这3个量可以唯一地确定一个状态,我用了一个三维数组cache[11][11][11]保存结果,避免重复运算。见main1()。
/*
ID: thestor1
LANG: C++
TASK: poj1664
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
int cache[11][11][11];
int DFS(int m, int last, int n, const int N)
{
// cout << "[debug]m: " << m << ", last: " << last << ", n: " << n << endl;
if (n == 0)
{
assert (m == 0);
return 1;
}
if (m == 0)
{
return 1;
}
if (cache[m][last][n] >= 0)
{
return cache[m][last][n];
}
cache[m][last][n] = 0;
for (int i = m / n; i <= min(last, m); ++i)
{
cache[m][last][n] += DFS(m - i, i, n - 1, N);
}
return cache[m][last][n];
}
int main1()
{
int T, M, N;
cin >> T;
for (int m = 0; m <= 10; ++m)
{
for (int last = 0; last <= 10; ++last)
{
for (int n = 0; n <= 10; ++n)
{
cache[m][last][n] = -1;
}
}
}
for (int t = 0; t < T; ++t)
{
cin >> M >> N;
DFS(M, M, N, N);
cout << cache[M][M][N] << endl;
}
return 0;
}
int main()
{
int T, M, N;
cin >> T;
int DP[11][11];
for (int m = 1; m <= 10; ++m)
{
DP[m][0] = 0;
}
for (int n = 0; n <= 10; ++n)
{
DP[0][n] = 1;
}
for (int m = 1; m <= 10; ++m)
{
for (int n = 1; n <= 10; ++n)
{
if (m >= n)
{
DP[m][n] = DP[m - n][n] + DP[m][n - 1];
}
else
{
DP[m][n] = DP[m][n - 1];
}
// cout << "[debug]m: " << m << ", n: " << n << ", DP[m][n]: " << DP[m][n] << endl;
}
}
for (int t = 0; t < T; ++t)
{
cin >> M >> N;
cout << DP[M][N] << endl;
}
return 0;
}