程序员数据结构笔记5

第五天 


回溯法:
  回溯跟递归都是程序员考试里常出现的问题,大家必须掌握!
  回溯法的有关概念:
  1) 解答树:叶子结点可能是解,对结点进行后序遍历.
  2) 搜索与回溯
  五个数中任选三个的解答树(解肯定有三层,至叶子结点): 
               ROOT 虚根
        /      /    |  /  /
        1      2     3  4   5
    /  |  |  /  / | /    //  |
    2  3  4  5 3 4 5  4 5  5
   /|/  // |  // | |
   3 4 5 4 5 5 4 5 5 5

  回溯算法实现中的技巧:栈
  要搞清回溯算法,先举一个(中序遍历二叉树的非递归算法)来说明栈在非递归中所起的作用。
      A 过程:push()->push()->push()->push()栈内结果:ABDE(E为叶子,结束进栈)
     / /   pop()   ABD(E无右孩子,出栈)
     B  C   pop()   AB(D无右孩子,出栈) 
    //     pop()   A(B有右孩子,右孩子进栈)
    D F     .      .
   / //     .      .
   E G H    .      .
  /        .      .
  I        最后结果: EDBGFIHAC
  简单算法:
    …
   if(r!=NULL) //树不空
   { while(r!=NULL) 
    { push(s,r);
     r=r->lch;   //一直向左孩子前进
    }
    while(!empty(s)) // 栈非空,出栈
    { p=pop(s);
     printf(p->data);
     p=p->rch;   //向右孩子前进
     while(p!=NULL)
     { push(s,p);
      p=p->lch; //右孩子进栈
     }
    } 
   } //这就是传说中的回溯,嘻嘻……没吓着你吧

  5选3问题算法:
  思想: 进栈:搜索
  出栈:回溯
  边建树(进栈)边遍历(出栈)
  基本流程: 
  太复杂了,再说我不太喜欢用WORD画图(有损形象),以后再整理!

  程序: n=5;r=3
     ……
     init(s)  //初始化栈
     push(s,1) //根进栈
     while(s.top<r-1)&&(s.data[s.top]!=n) //有孩子
      push(s,s.data[s.top]+1); //孩子入栈
     while(!empty(s))
     { if(s.top=r-1)
      判断该"解"是否为解.
      x=pop(s); //保留x,判断是否为最大值n,如果是n,则出栈
      while(x==n)
      x=pop(s);
      push(s,x+1);
      while(s.top<r-1)&&(s.data[s.top]!=n)
      push(s,s.data[s.top]+1);
     }

  背包问题: TW=20 , w[5]={6,10,7,5,8} 
  解的条件:1) 该解答树的叶子结点
  2) 重量最大
  解答树如下:   ROOT
       / | | | /
          6 10   7   5  8
        / | | /  / | /  / / | 
        10 7 5 8 7 5 8 5  8 8
         | |      | 
         5 8      8
  程序:
  temp_w 表示栈中重量和
  …
  init(s); //初始化栈
  i=0;
  While(w[i]>TW)
   i++;
   If(i==n) Return -1; //无解
   Else {
    Push(s,i);
    Temp_w=w[i];
    i++;
    while(i<n)&&(temp_w+w[i]<=TW)
     { push(s,i);
      temp_w+=w[i];
      i++;
    }
    max_w=0;
    while(!empty(s))
     { if(max_w<temp_w)
       max_w=temp_w;
       x=pop(s);
       temp_w-=w[x];
       x++;
       while(x<n)&&(temp_w+w[x]>TW)
        x++;
       while(x<n)
       { push(s,x);
        temp_w=temp_w+w[x];
        x++;
        while(x<n)&&(temp_w+w[x]>TW)
        x++;
       }
     }
  请大家思考:四色地图问题,比如给中国地图涂色,有四种颜色,每个省选一种颜色,相邻的省不能取同样的颜色.不许偷懒,不能选人口不多于xxxxW的"大国"哦!如果真的有一天台湾独立了,下场就是这样了,一种颜色就打发了,不过台湾的程序员们赚到了,省事!呵呵。

贪婪法:
  不求最优解,速度快(以精确度换速度)

  例:哈夫曼树,最小生成树

  装箱问题:
  有n个物品,重量分别为w[n],要把这n个物品装入载重为TW的集装箱内,需要几个集装箱?
  思想1:对n个物品排序
  拿出第1个集装箱,从大到小判断能不能放。
  2 …
  3 …
  . …
  . …
  思想2: 对n个物品排序
  用物品的重量去判断是否需要一只新箱子,如果物品重量小于本箱子所剩的载重量,则装进去,反之则取一只新箱子。

  程序:
  count=1;qw[0]=TW;
  for(i=0;i<n;i++)
  {
   k=0;
   while(k<count)&&(w[i]>qw[k])
    k++;
    if(w[i]<=qw[k])
     qw[k]=qw[k]-w[i];
     code[i]=k; //第i个物品放在第k个箱子内
    else
     {count++; //取一个新箱子
      qw[count-1]=TW-w[i];
      code[i]=count-1;
    }
  }

  用贪婪法解背包问题:
  n个物品,重量:w[n] 价值v[i]
  背包限重TW,设计一个取法使得总价值最大.
  方法:
   0  1  2  3 … n-1
   w0  w1  w2  w3 … wn-1
   v0  v1  v2  v3 … vn-1 
   v0/w0  …     v(n-1)/w(n-1) 求出各个物品的"性价比"

  先按性价比从高到低进行排序

  已知:w[n],v[n],TW
  程序:
  …
  for(I=1;I<n;I++)
   d[i]=v[i]/w[i]; //求性价比
   for(I=0;I<n;I++)
   { max=-1;
    for(j=0;j<n;j++)
    { if(d[j]>max)
     { max=d[j];x=j; }
    } 
    e[i]=x;
    d[x]=0;
   }
   temp_w=0;temp_v=0;
  for(i=0;i<n;i++)
   { if(temp_w+w[e[i]]<=TW)
     temp_v=temp_v+v[e[v]];
  }

分治法:
  思想:把规模为n的问题进行分解,分解成几个小规模的问题.然后在得到小规模问题的解的基础上,通过某种方法组合成该问题的解.

  例:数轴上有n个点x[n],求距离最小的两个点.
  分:任取一点,可以把x[i]这n个点分成两个部分
  小的部分 分点 大的部分
    |_._.__.__.____._|__._._.__._.__._______._.__._._.__.___._____._|
  治:解=min{小的部分的距离最小值;
   大的部分的距离最小值;
   大的部分最小点和小的部分最大点这两点之差;}

你可能感兴趣的:(数据结构,c,算法,null,ini)