POJ 1664 解题报告

1664Accepted220K0MSC++1766B
1664Accepted232K16MSC++1175B
这道题用了两种解法,一种是DP(0MS),另一种是DFS(也可以改成DP,16MS)。由于要避免重复,可以假设所有盘子都已经按照所放苹果数目递增排序。

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;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值