1、题目描述
NowCoder每天要给很多人发邮件。有一天他发现发错了邮件,把发给A的邮件发给了B,把发给B的邮件发给了A。于是他就思考,要给n个人发邮件,在每个人仅收到1封邮件的情况下,有多少种情况是所有人都收到了错误的邮件?
即没有人收到属于自己的邮件。
他给的测试用例和输入输出描述是这样的:
我说这道题是典型的动态规划,没人反驳吧。
题解
n个邮件放入n个邮箱,我们用D(n)表示,那么D(n-1)的意思就是说n-1个邮件放入n-1个邮箱
- 第一步:我们将第n个邮件,放入一个邮箱,那么共有n-1种情况,假设他放入了第k个邮箱
- 第二步:放入第k个邮箱后,那就有两种情况:1、k邮箱所对应的第k号邮件,也恰好放入了第一步里面第n个邮件所对应的n号邮箱,那剩下的n-2个元素就是有D(n-2)种方法 2、k邮箱的邮件并没有放入第n个邮箱,那就是剩下的n-1个元素就有D(n-1)种方法。
特殊的,我们还知道D(1)=0,D(2)=1;
那我们的递推方程就出来了:D(n)=(n-1)*[D(n-1)+D(n-2)]
C++代码
前括弧 代码真的好简短 后括弧
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
long long res[21] = { 0,0,1 };
for (int i = 3; i < 21; i++)
{
res[i] = (i - 1)*(res[i - 1] + res[i - 2]);
}
int n;
while (cin >> n)
{
cout << res[n] << endl;
}
system("pause");
return 0;
}
2、题目描述
广场上站着一支队伍,她们是来自全国各地的扭秧歌代表队,现在有她们的身高数据,请你帮忙找出身高依次递增的子序列。 例如队伍的身高数据是(1、7、3、5、9、4、8),其中依次递增的子序列有(1、7),(1、3、5、9),(1、3、4、8)等,其中最长的长度为4。
咱再来看下测试用例的输入输出 :
我先说哈,我的代码在VS上跑过了,在牛客上没跑过,时间复杂度太大了,循环太多超时了,所以先放在这,等我学的好点了再来改进。
我的思路:先以第一个数为基准,max记录他的下标,从他往后找第一个比他大的数,max记录他的下标并把该数写入数组,一直找到结束。在进行找第二个比他大的数,max记录下标一直到结束。这一轮结束后,在以第二个数为基准,找比他大的数,依次类推。
代码:
//时间复杂度太大了,最后强调一遍
int TheMaxLength(vector<int> a)
{
int max = 0;
vector<int> ret;
for (int i = 0; i < a.size(); i++)
{
int max1 = i;
for (int j = i + 1; j < a.size(); j++)
{
ret.push_back(a[i]);
if (a[j] > a[i])
{
max1 = j;
ret.push_back(a[j]);
}
for (int k = max1+1; k < a.size(); k++)
{
if (a[k] > a[max1])
{
max1 = k;
ret.push_back(a[k]);
}
}
if (ret.size() > max)
max = ret.size();
ret.clear();
}
}
return max;
}