一本书看三年,无聊到爆
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大)
代码: