2012hulu笔试题

========================================
1、1,2,3...n入栈,问有多少种出栈的可能性,递归式和解析式。
百度百科中卡特兰数:http://baike.baidu.com/view/2499752.htm#1
原理:
  • 令h(0)=1,h(1)=1,catalan数满足递推式[1]: h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)
有:h(0)=1, h(1)=1, h(2)=2, h(3)=5, 14, ...
  • 递推关系的解为:   h(n)=C(2n,n)/(n+1) (n=1,2,3,...)   
  • 递推关系的另类解为:   h(n)=c(2n,n)-c(2n,n+1)(n=1,2,3,...)
应用:
     关键是把原问题分解成 不相交的子问题的并集。
     举例:
  • n个数的入栈问题——假如数k为第一个出栈的数,那么k把1~n分成了两组,1~k-1和k+1~n,而k可取1~n中的任意数,故:f(n) = f(0)*f(n-1) + f(1)*f(n-2) + f(2)*f(n-3) + ... + f(n-1)*f(0), 令f(0)=f(1)=1;我们有f(n) = h(n).
  • 矩阵乘法的括号化问题——每次用两个括号,把a1~an分成两份,a1~ak,ak+1~an,k=1,2,3...n-1,而这两段又组成了两个独立的子问题。于是:f(n) = f(1)*f(n-1) + f(2)*f(n-2) + ... f(n-1)*f(1),令f(1)=1. 我们有f(n) = h(n-1).
  • n个节点构造二叉树问题——此处应该是认为每个节点都一样。取出根节点,设左子树有k个节点k=0,1,2,...n-1,则右子树有n-k-1个节点,故:f(n) = f(0)*f(n-1) + f(1)*f(n-2) +... + f(n-1)*f(0),令f(0)=1;我们有f(n) = h(n).
  • 常见的例子还有:买票找零问题,凸多边形三角划分问题,不越过对角线的上班路线问题。

========================================
2、八皇后问题——递归解和非递归解
下面两个程序分别来自于:
程序注释比较详细,不再赘述,直接上代码吧。
递归解
//   回溯法解八皇后问题。
/* Code by Slyar */
#include   <stdio.h>
#include   <stdlib.h>

#define   max   8

int   queen   [ max ],   sum =0;   /* max   为棋盘最大坐标,queen[i]标识第i行的皇后放置在第queen[i]列  */

void   show   ()   /*   输出所有皇后的坐标   */
{
          int   i   ;
          for ( i   = 0;   i   <   max ;   i   ++)
       {
                 printf ( "(%d,%d) "   ,   i ,   queen [ i   ]);
       }
          printf ( "\n"   );
          sum ++;
}

int   check   ( int   n )   /*   检查当前列能否放置皇后   */
{
          int   i   ;
          for ( i   = 0;   i   <   n ;   i   ++)   /*   检查横排和对角线上是否可以放置皇后   */
       {
                 if ( queen   [ i ] ==   queen [ n   ] ||   abs (   queen [ i   ] -   queen [   n ]) == ( n   -   i ))
              {
                        return   1;
              }
       }
          return   0;
}

void   put   ( int   n )   /*   回溯尝试皇后位置   ,n 为横坐标 */
{
          int   i   ;
          for ( i   = 0;   i   <   max ;   i   ++)
       {      
                 queen [ n   ] =   i ;   /*   将皇后摆到当前循环到的位置   */
                 if (! check   ( n ))
              {          
                        if ( n   ==   max   - 1)
                     {
                              show ();   /*   如果全部摆好,则输出所有皇后的坐标   */
                     }        
                        else
                     {
                              put ( n   + 1);   /*   否则继续摆放下一个皇后   */
                     }
              }
       }
}

int   main   ()
{
          put (0);   /*   从横坐标为开始依次尝试   */
          printf ( "%d"   ,   sum );
          system ( "pause"   );
          return   0;
}

非递归解:
/**
* 回溯法解N 皇后问题
* 使用一个一维数组表示皇后的位置
* 其中数组的下标表示皇后所在的行
* 数组元素的值表示皇后所在的列
* 这样设计的棋盘,所有皇后必定不在同一行,于是行冲突就不存在了
* date  : 2011-08-03 
* author: liuzhiwei
**/ 

#include <stdio.h>   
#include <stdlib.h>   
#include <math.h>   

#define QUEEN 8     //皇后的数目  
#define INITIAL -10000   //棋盘的初始值  

int a [QUEEN];    //一维数组表示棋盘 

void init ()  //对棋盘进行初始化  
        int *p 
        for (p = a; p < a + QUEEN; ++ p)  
       { 
              * p = INITIAL 
       } 
}  

int valid (int row, int col)    //判断第row 行第col列是否可以放置皇后  
        int i 
        for (i = 0; i < QUEEN; ++i )   //对棋盘进行扫描  
       { 
               if (a [i] == col || abs (i - row) == abs (a[ i] - col ))   //判断列冲突与斜线上的冲突  
                      return 0; 
       } 
        return 1; 
}  

void print ()    //打印输出 N皇后的一组解 
        int i , j
        for (i = 0; i < QUEEN; ++i 
       { 
               for (j = 0; j < QUEEN; ++j 
              { 
                      if (a [i] != j)      //a[i] 为初始值 
                            printf("%c " , '.'); 
                      else                //a[i]表示在第i 行的第a[i]列可以放置皇后  
                            printf("%c " , '#'); 
              } 
               printf("\n" ); 
       } 
        for (i = 0; i < QUEEN; ++i 
               printf("%d " , a[ i]); 
        printf("\n" ); 
        printf("--------------------------------\n" ); 

void queen ()      //N皇后程序  
        int n = 0; 
        int i = 0, j = 0; 
        while (i < QUEEN
       { 
               while (j < QUEEN)        //i 行的每一列进行探测,看是否可以放置皇后  
              { 
                      if(valid (i, j))      // 该位置可以放置皇后  
                     { 
                            a[i ] = j;        //i 行放置皇后  
                            j = 0;           // i行放置皇后以后,需要继续探测下一行的皇后位置,所以此处将 j清零,从下一行的第列开始逐列探测  
                            break
                     } 
                      else 
                     { 
                           ++ j;             //继续探测下一列  
                     } 
              } 
               if(a [i] == INITIAL)         // i行没有找到可以放置皇后的位置  
              { 
                      if (i == 0)             //回溯到第一行,仍然无法找到可以放置皇后的位置,则说明已经找到所有的解,程序终止  
                            break
                      else                    //没有找到可以放置皇后的列,此时就应该回溯  
                     { 
                           -- i
                            j = a [i] + 1;        //把上一行皇后的位置往后移一列  
                            a[i ] = INITIAL;      //把上一行皇后的位置清除,重新探测  
                            continue
                     } 
              } 
               if (i == QUEEN - 1)          //最后一行找到了一个皇后位置,说明找到一个结果,打印出来  
              { 
                      printf("answer %d : \n" , ++n); 
                      print(); 
                      //不能在此处结束程序,因为我们要找的是 N皇后问题的所有解,此时应该清除该行的皇后,从当前放置皇后列数的下一列继续探测。  
                      //_sleep(600);  
                      j = a [i] + 1;             //从最后一行放置皇后列数的下一列继续探测  
                      a[i ] = INITIAL;           //清除最后一行的皇后位置  
                      continue
              } 
              ++ i;              //继续探测下一行的皇后位置  
       } 

int main (void
        init(); 
        queen(); 
        system("pause" ); 
        return 0; 
}  

========================================
3、背包问题——设定完成时间限制的01背包问题
背包问题主要的参考资料非《背包九讲》莫属。   http://wenku.baidu.com/view/8b3c0d778e9951e79b892755.html
背包问题概括下来,精华在于01背包、完全背包、多重背包三个问题的解上面。
  • 01背包:   f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

for i=1..N

    for v=V..0

        f[v]=max{f[v],f[v-c[i]]+w[i]}
  • 完全背包:f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}

for i=1..N

    for v=0..V

        f[v]=max{f[v],f[v-cost]+weight}
  • 多重背包:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]} 这是最直观的方法,还有就是可以把k用二进制表示,这样可以降低时间复杂度。
     procedure MultiplePack(cost,weight,amount)

    if cost*amount>=V

        CompletePack(cost,weight)

        return

    integer k=1

    while k<num

        ZeroOnePack(k*cost,k*weight)

        amount=amount-k

        k=k*2

    ZeroOnePack(amount*cost,amount*weight)

对于二维费用的问题,直接再加一维即可。
f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]}

2012-10-03





















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值