Chinaunix首页 | 论坛 | 博客
  • 博客访问: 20786
  • 博文数量: 4
  • 博客积分: 130
  • 博客等级: 入伍新兵
  • 技术积分: 60
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-22 20:05
文章分类
文章存档

2012年(4)

我的朋友

分类: C/C++

2012-10-31 10:05:13

有n个球和n个盒子,编号为1, 2, 3, ... n;
一个盒子放一个球,k球不能放入k盒;
共有几种放法?

想象一下,a球放b盒,b球放c盒,c球放d盒,如此下去,必定是一个环或者多个环,且是一个有向图。
假设n=4,则一下情况都是满足的:
1->2, 2->3, 3->4, 4->1;(单环)
1->3, 3->2, 2->4, 4->1;(单环)
1->4, 4->1, 2->3, 3->2;(两个环)

因为一个盒子只能放一个球,所以不可能有a->b, a->c和a->c, b->c的情况,即有向图只能是环。
因为相同号的盒子不能放球,所以每个环至少有两个节点。

解决思路:动态规划
f(i)表示i个球有f(i)种方法;
另f(0) = 1, f(1) = 0;
f(2) = 1;(1->2, 2->1)
f(3) = 2;(1->2, 2->3, 3->1; 1->3, 3->2, 2->1)
.
.
.
f(n+1) = C(n,1)*A(1,1)*f(n-1) + C(n,2)*A(2,2)*f(n-2) + ... + C(n,k)*A(k, k)*f(n-k) + ... + C(n,n)*A(n,n)*f(n-n)

对于n+1号球,它可以与1个球组成2环,与2个球组成3环,。。。与n个球组成n+1环,这是它的所有情况了;
与k个球组成k+1环时:
我们先从前n个球任意取k个球C(n, k);
n+1号球与这k个球组成一个环,共有A(k,k)种情况,注意不是A(k+1, k+1),假如四个球排一个环(1->2, 2->3, 3->4, 4->1和4->1, 1->2, 2->3, 3->4是一样的);
然后剩下n-k个球有f(n-k)种情况。
所以n+1号球在一个k+1环里共有C(n,k)*A(k,k)*f(n-k)中情况。
ps:当k=n-1时,此时n+1号球是组成了n环,剩下一个球,这是不符合的,不过前面我们已经定义f(1)=0,所以转换方程是没问题的。


点击(此处)折叠或打开

  1. #include <string.h>
  2. #include <iostream>
  3. using namespace std;

  4. int factorial(int n) {
  5.     int i = n;
  6.     if(n <= 1)
  7.         return 1;
  8.     while(i > 1) {
  9.         --i;
  10.         n *= i;
  11.     }
  12.     return n;
  13. }

  14. int A(int n, int m) {
  15.     return factorial(n)/factorial(n - m);
  16. }

  17. int C(int n, int m) {
  18.     return A(n, m)/factorial(m);
  19. }

  20. int f(int n, int *dp) {
  21.     int i, j;
  22.     dp[0] = 1;
  23.     dp[1] = 0;
  24.     for(i = 2; i <= n; ++i) {
  25.         dp[i] = 0;
  26.         for(j = 1; j < i; ++j) {
  27.             dp[i] += C(i - 1, j) * A(j, j) * dp[i - 1 - j];
  28.         }
  29.     }
  30.     return 0;
  31. }

  32. int main() {
  33.     int *dp;
  34.     int n;
  35.     int i;
  36.     cout << "input:";
  37.     cin >> n;
  38.     dp = new int[n + 1];
  39.     f(n, dp);
  40.     for(i = 0; i <= n; ++i) {
  41.         cout << i << ":" << dp[i] << endl;
  42.     }
  43.     delete [] dp;
  44.     return 0;
  45. }



阅读(1590) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~