一本书看三年,无聊到爆

O
|<█
/\

不如向别人借

O        O      O
|<█   ▄/|\   ▓>|
/\         /\       /\

有n个人,每人有一本书,看厌了,想向对方借书,问有多少种借法?(12345 => 23514 算一种借法)

【输入】

一个整数n,表示人数

【输出】

所有书的借法数

【样例输入】

4

【样例输出】

9

【输出说明】

2143

2341

2413

3142

3412

3421

4123

4312

4321

这道题我的第一印象是搜索。

 1 #include<iostream>
 2 using namespace std;
 3 int n,sum=0;
 4 bool tk[100];
 5 void put(int cur)
 6 {
 7     if(cur>n)
 8     {
 9         sum++;
10         return;
11     }
12     for(int i=1;i<=n;i++)
13     {
14         if(i!=cur&&!tk[i])
15         {
16             tk[i]=1;
17             put(cur+1);
18             tk[i]=0;
19         }
20     }
21 }
22 int main()
23 {
24     cin>>n;
25     put(1);
26     cout<<sum;
27     return 0;
28 }

但是

这代码的时间

吓得我“跳楼了”(TLE)
        O
        /|
         >
-------+
          |
----+   |
      |   |

还不如直接递推,或许只需要几个公式解决

先定义m个人m本书借书的方法数为f(m)。
第一步,把第n本书借给某一个人,比如第k个,一共有n-1种方法;
第二步,第k本书有两种情况可被借:⑴被第n个人借走,那么,对于剩下的n-1本书,由于第k本书被第n个人借走,则剩下n-2本书就有f(n-2)种借法;⑵第k本书不被第n个人借走,这时,对于剩下n-1本书,有f(n-1)种借法;
综上得到
f(n) = (n-1)*(f(n-2) + f(n-1))
边界条件:f(1) = 0,f(2) = 1,f(3)=2
 1 #include<iostream>
 2 using namespace std;    
 3 int main()
 4 {
 5     int n;
 6     cin>>n;
 7     int f[105]={0,0,1,2};
 8     for(int i=4;i<=n;i++)
 9         f[i]=(i-1)*(f[i-1]+f[i-2]);
10     cout<<f[n];
11     return 0;
12 }

(后来我才发现答案tei大)

代码: