红桃J

用心写好每行完美的代码,远比写一堆更有价值

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

分析以下代码

int dp(int i)
{
  int& ans=d[i];    //为该表项声明一个引用,简化对它的读写操作。 
  if(ans>0) return ans;
  ans=1;
  for(int j=0;j<n;j++){
    if(G[i][j]){
      int tmp=dp(j);
      ans=ans>tmp+1?ans:tmp+1; 
    }
  }
  return ans;
}

这是个DAG下的动态规划。是矩形嵌套的dp函数。粘这个代码的原因是为了反复体会这个ans在这个递归函数中的使用技巧。for语句块是为了选出当前行下的dp(j)的最大值,然后ans在此充当了max的作用。

 

下面这个是八皇后问题的递归代码

void solve(int i, int n)
{
    if(i == n)
    {
        print(n);
        printf("\n");
        num++;
    }
    else
        for(int j =0;j<n ;j++)
        {
            A[i][j]=1;
            if(IsLegal(i,j,n))
            {
                solve(i+1,n);
            }
            A[i][j]=0;
        }
}
for(int j =0;j<n ;j++)
{
    A[i][j]=1;
    if(IsLegal(i,j,n))
    {
         solve(i+1,n);
    }
    A[i][j]=0;
}

仔细看这个for循环,当尝试到第i行的第j列时,这时的目的是判断(i,j)这个位置是否合法,如果合法就在标识数组中填1,如果不合法就填0。这时我们很容易把代码写成这个样子

for(int j =0;j<n ;j++)
{
    if(IsLegal(i,j,n))
    {
                A[i][j]=1;
        solve(i+1,n);
    }
}

如果按照这种写法,分析一下:假如当前的(i,j)合法,然后我们把A[i][j]赋值为1,然后进入solve(i+1,n)的函数如果此时不能在该层找到合法的位置,退回上层,继续刚才未完成的for循环,所以A[i][j]此时等于1,而为得到更改。所以第二种方法错误。

这就是对于递归函数常犯的忘记修改标识变量的错误。

posted on 2014-08-06 14:59  红桃J  阅读(181)  评论(0编辑  收藏  举报