【解题记录】排列小球

题目连接:https://leetcode-cn.com/leetbook/read/didiglobal2/e7hh2i/
题目来源:力扣(LeetCode)ios

题目描述:数组

给定三种类型的小球 P、Q、R,每种小球的数量分别为 np、nq、nr 个。如今想将这些小球排成一条直线,可是不容许相同类型的小球相邻,问有多少种排列方法。如若 np=2,nq=1,nr=1 则共有 6 种排列方式:PQRP,QPRP,PRQP,RPQP,PRPQ 以及 PQPR。若是没法组合出合适的结果,则输出 0。spa

输入描述:
一行以空格相隔的三个数,分别表示为 np,nq,nr。code

输出描述:blog

排列方法的数量。递归

输入样例:
2 1 1ci

输出样例:
6leetcode

解题思路:io

按排列中第一个小球的类型不一样(P、Q或R),可将排列分为三类。总排列数为三类排列数的总和。设总的合法排列数为fall,第一个球为P的合法排列数为fp(np, nq, nr),第一个小球为Q的合法排列数为fq(np, nq, nr),第一个小球为R的合法排列数为fr(np, nq, nr)。则有:class

fall = fp(np, nq, nr) + fq(np, nq, nr) + fr(np, nq, nr)

对于fp(np, nq, nr):

1. 若np <= 0,此时没法取出一个P小球放到排列的第一位,所以第一个球为P的合法排列数为0。

2. 若np == 1且nq == 0, nr == 0,此时取出一个P小球放到排列第一位之后,全部的小球都已用尽且不会有相同的小球相临。所以合法的排列数为1。

3. 若为其它状况,在取出一个P小球放到排列第一位之后,剩余的小球为:np - 1个P小球,nq个Q小球,nr个R小球。要使排列合法,在对剩余小球进行排列时,须要将Q球或者R球放在第一位并保证后续排列合法,所以此时有:fp(np, nq, nr) = fq(np - 1, nq, nr) + fr(np - 1, nq, nr)。

对于fq(np, nq, nr)与fr(np, nq, nr)可作相似的分析。

至此,可经过将原来的问题一步步分解成规模更小的相同问题进行递归求解。经过一个辅助的多维数组记录递归过程当中产生的重复状态来提升运算效率。代码以下:

#include <iostream>
#include <vector>

using namespace std;

int64_t fp(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec);
int64_t fq(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec);
int64_t fr(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec);

int64_t fp(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec)
{
	if (np <= 0)
		return 0;
	if (np == 1 && nq == 0 && nr == 0)
		return 1;

	if (rec[0][np][nq][nr] == -1)
	{
		rec[0][np][nq][nr] = fq(np - 1, nq, nr, rec) + fr(np - 1, nq, nr, rec);
	}

	return rec[0][np][nq][nr];
}

int64_t fq(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec)
{
	if (nq <= 0)
		return 0;
	if (np == 0 && nq == 1 && nr == 0)
		return 1;

	if (rec[1][np][nq][nr] == -1)
	{
		rec[1][np][nq][nr] = fp(np, nq - 1, nr, rec) + fr(np, nq - 1, nr, rec);
	}

	return rec[1][np][nq][nr];
}

int64_t fr(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec)
{
	if (nr <= 0)
		return 0;
	if (np == 0 && nq == 0 && nr == 1)
		return 1;

	if (rec[2][np][nq][nr] == -1)
	{
		rec[2][np][nq][nr] = fp(np, nq, nr - 1, rec) + fq(np, nq, nr - 1, rec);
	}

	return rec[2][np][nq][nr];
}


int main()
{
	int np, nq, nr;
	cin >> np >> nq >> nr;
	vector<vector<vector<vector<int64_t> > > > rec(3, vector<vector<vector<int64_t > > >(np + 1, vector<vector<int64_t> >(nq + 1, vector<int64_t>(nr + 1, -1))));
	int64_t res = fp(np, nq, nr, rec) + fq(np, nq, nr, rec) + fr(np, nq, nr, rec);
	cout << res << endl;
	//system("pause");
	return 0;
}

总结:

应该是个基础的动态规划题目吧,代码写得确实有点烂,不过懒得改了,就这样,再接再励吧。

相关文章
相关标签/搜索