zoukankan      html  css  js  c++  java
  • Dfs学习经验(纸上运行理解DFS)【两道题】

      首先我想吐槽的是,在CSDN上搞了好久还是不能发博客,就是点下发表丝毫反应都没有的,我稍微百度了几次还是没有找到解决方法,在CSDN的BBS上也求助过管理员但是没有收到答复真是烦躁,导致我新生入学以来没能很好的在博客上记录点什么,有些想法只是在脑中灵光一现然后事后就不好想起来了。后来发现了除了CSDN还有ITeye、cnblogs等一些其他优秀的博客网站…。废话不多说了,现在开始吧。

     

    背景:在大一上学期的第六次C语言课后练习中碰到了这样一题

     

    放苹果(POJ1664

    题目描述

    把M个同样的苹果放在N个同样的盘子里,允许有盘子空,问共有多少种不同分法
    注意:5,1,1和1,5,1是同一种。

    输入

    第一行是测试数据数目t(0~20),以下t行均包含两个整数M,N,空格分开。
    1<=M,N<=10;

    输出

    对每行数据,输出相应的k。

    样例输入

    1

    7 3

    样例输出

    8

     

    审题思考:

    在经过小范围数据的纸上运行后,发现了这么一个规律:

    0 0 0

    0 0 7 OK

    0 1 1

    0 1 6 OK

    0 2 2

    0 2 5 OK

    0 3 3

    0 3 4 OK

    0 4 4

    0 5 5

    0 6 6

    0 7 7

    1 1 1

    1 1 5 OK

    ……

    于是,按照这个规律,我试着这么写:

    当M=7,N=3的时候:

     1 if(N==3)
     2             {
     3                 for(i=0;i<M;i++)
     4                 {
     5                     for(j=i;j<M;j++)
     6                     {
     7                         for(k=j;k<=M;k++)
     8                         {
     9                             if((i+j+k)==M)
    10                             {
    11                                 ti++;
    12                                 break;
    13                             }
    14                         }
    15                     }
    16                 }
    17                 printf("%d
    ",ti);
    18             }

    同理,N在1-10这10个数中,都可以利用此种多重FOR循环嵌套进行搜索判断

    按照这种规律,我完整的写了一遍这题,但是发现提交上去WA

    以下是我完整的代码:

      1 #include<stdio.h>
      2 int main()
      3 {
      4     int n,i,j,k,M,N,ti,i4,i5,i6,i7,i8,i9,i10;
      5     while(scanf("%d",&n)!=EOF)
      6     {
      7         while(n--)
      8         {
      9             ti=0;
     10             scanf("%d%d",&M,&N);
     11             if(N==1)
     12                 printf("1
    ");
     13             if(N==2)
     14             {
     15                 for(j=0;j<M;j++)
     16                 {
     17                     for(k=j;k<=M;k++)
     18                     {
     19                         if((j+k)==M)
     20                         {
     21                             ti++;
     22                             break;
     23                         }
     24                     }
     25                 }
     26                 printf("%d
    ",ti);
     27             }
     28             if(N==3)
     29             {
     30                 for(i=0;i<M;i++)
     31                 {
     32                     for(j=i;j<M;j++)
     33                     {
     34                         for(k=j;k<=M;k++)
     35                         {
     36                             if((i+j+k)==M)
     37                             {
     38                                 ti++;
     39                                 break;
     40                             }
     41                         }
     42                     }
     43                 }
     44                 printf("%d
    ",ti);
     45             }
     46             if(N==4)
     47             {
     48                 for(i4=0;i4<M;i4++)
     49                 {
     50                     for(i=i4;i<M;i++)
     51                     {
     52                         for(j=i;j<M;j++)
     53                         {
     54                             for(k=j;k<=M;k++)
     55                             {
     56                                 if((i4+i+j+k)==M)
     57                                 {
     58                                     ti++;
     59                                     break;
     60                                 }
     61                             }
     62                         }
     63                     }
     64                 }
     65                 printf("%d
    ",ti);
     66             }
     67             if(N==5)
     68             {
     69                 for(i5=0;i5<M;i5++)
     70                 {
     71                       for(i4=i5;i4<M;i4++)
     72                     {
     73                         for(i=i4;i<M;i++)
     74                         {
     75                             for(j=i;j<M;j++)
     76                             {
     77                                 for(k=j;k<=M;k++)
     78                                 {
     79                                     if((i5+i4+i+j+k)==M)
     80                                     {
     81                                         ti++;
     82                                         break;
     83                                     }
     84                                 }
     85                             }
     86                         }
     87                     }
     88                 }
     89                 printf("%d
    ",ti);
     90             }
     91             if(N==6)
     92             {
     93                 for(i6=0;i6<M;i6++)
     94                 {
     95                       for(i5=i6;i5<M;i5++)
     96                     {
     97                           for(i4=i5;i4<M;i4++)
     98                         {
     99                             for(i=i4;i<M;i++)
    100                             {
    101                                 for(j=i;j<M;j++)
    102                                 {
    103                                     for(k=j;k<=M;k++)
    104                                     {
    105                                         if((i6+i5+i4+i+j+k)==M)
    106                                         {
    107                                             ti++;
    108                                             break;
    109                                         }
    110                                     }
    111                                 }
    112                             }
    113                         }
    114                     }
    115                 }
    116                 printf("%d
    ",ti);
    117             }
    118             if(N==7)
    119             {
    120                 for(i7=0;i7<M;i7++)
    121                 {
    122                     for(i6=0;i6<M;i6++)
    123                     {
    124                           for(i5=i6;i5<M;i5++)
    125                         {
    126                               for(i4=i5;i4<M;i4++)
    127                             {
    128                                 for(i=i4;i<M;i++)
    129                                 {
    130                                     for(j=i;j<M;j++)
    131                                     {
    132                                         for(k=j;k<=M;k++)
    133                                         {
    134                                             if((i7+i6+i5+i4+i+j+k)==M)
    135                                             {
    136                                                 ti++;
    137                                                 break;
    138                                             }
    139                                         }
    140                                     }
    141                                 }
    142                             }
    143                         }
    144                     }
    145                 }
    146                 printf("%d
    ",ti);
    147             }
    148             if(N==8)
    149             {
    150                 for(i8=0;i8<M;i8++)
    151                 {
    152                     for(i7=0;i7<M;i7++)
    153                     {
    154                         for(i6=0;i6<M;i6++)
    155                         {
    156                               for(i5=i6;i5<M;i5++)
    157                             {
    158                                   for(i4=i5;i4<M;i4++)
    159                                 {
    160                                     for(i=i4;i<M;i++)
    161                                     {
    162                                         for(j=i;j<M;j++)
    163                                         {
    164                                             for(k=j;k<=M;k++)
    165                                             {
    166                                                 if((i8+i7+i6+i5+i4+i+j+k)==M)
    167                                                 {
    168                                                     ti++;
    169                                                     break;
    170                                                 }
    171                                             }
    172                                         }
    173                                     }
    174                                 }
    175                             }
    176                         }
    177                     }
    178                 }
    179                 printf("%d
    ",ti);
    180             }
    181             if(N==9)
    182             {
    183                 for(i9=0;i9<M;i9++)
    184                 {
    185                     for(i8=0;i8<M;i8++)
    186                     {
    187                         for(i7=0;i7<M;i7++)
    188                         {
    189                             for(i6=0;i6<M;i6++)
    190                             {
    191                                   for(i5=i6;i5<M;i5++)
    192                                 {
    193                                       for(i4=i5;i4<M;i4++)
    194                                     {
    195                                         for(i=i4;i<M;i++)
    196                                         {
    197                                             for(j=i;j<M;j++)
    198                                             {
    199                                                 for(k=j;k<=M;k++)
    200                                                 {
    201                                                     if((i9+i8+i7+i6+i5+i4+i+j+k)==M)
    202                                                     {
    203                                                         ti++;
    204                                                         break;
    205                                                     }
    206                                                 }
    207                                             }
    208                                         }
    209                                     }
    210                                 }
    211                             }
    212                         }
    213                     }
    214                 }
    215                 printf("%d
    ",ti);
    216             }
    217             if(N==10)
    218             {
    219                 for(i10=0;i10<M;i10++)
    220                 {
    221                     for(i9=0;i9<M;i9++)
    222                     {
    223                         for(i8=0;i8<M;i8++)
    224                         {
    225                             for(i7=0;i7<M;i7++)
    226                             {
    227                                 for(i6=0;i6<M;i6++)
    228                                 {
    229                                       for(i5=i6;i5<M;i5++)
    230                                     {
    231                                           for(i4=i5;i4<M;i4++)
    232                                         {
    233                                             for(i=i4;i<M;i++)
    234                                             {
    235                                                 for(j=i;j<M;j++)
    236                                                 {
    237                                                     for(k=j;k<=M;k++)
    238                                                     {
    239                                                         if((i10+i9+i8+i7+i6+i5+i4+i+j+k)==M)
    240                                                         {
    241                                                             ti++;
    242                                                             break;
    243                                                         }
    244                                                     }
    245                                                 }
    246                                             }
    247                                         }
    248                                     }
    249                                 }
    250                             }
    251                         }
    252                     }
    253                 }
    254                 printf("%d
    ",ti);
    255             }
    256         }
    257     }
    258     return 0;
    259 }
    View Code

    但是对于用这种方法解决这题我并不是很满意,虽然不知道为什么WA了。

    在查阅了相关资料后发现可以利用DFS的方式

    这里有一段关于解决这题的DFS相关函数:

     1  1 //代码来西电ACMPPT
     2  2 void dfs(long k, long w)    //初始k=1,w=0; k表示现在已用几个盘子,w表示已经放了几个苹果
     3  3 {                                         
     4  4   long i,u; 
     5  5   if (k==m)                     //当最后一个盘子被放置苹果的时候我们进行判断
     6  6     { 
     7  7         if (n-w>=s[k-1]) 
     8  8             { 
     9  9                s[k]=n-w; 
    10 10                z=z+1; 
    11 11             }
    12 12         return; 
    13 13     }
    14 14          for (i=0;i<=n;i++) 
    15 15              if (i>=s[k-1])           //如果当前放置的苹果个数大于前一个盘子继续放置
    16 16                { 
    17 17                   w=w+i; 
    18 18                   s[k]=i; k=k+1; 
    19 19                    dfs(k,w); 
    20 20                   w=w-i; 
    21 21                   k=k-1; 
    22 22                } 
    23 23 } 
    View Code

    当初看到这段简短的代码,我只是一眼看出了这是与递归相关的函数

    花了一段时间纸上运行后(在纸上写出详细步骤)

    大致写出我的纸上运行内容:

    以实例输入为5个苹果,3个盘子

    Start: k=1,w=0

    第一次进入DFS函数

    W=0,s[1]=0,k=2;

    第二次进入DFS函数

    W=0,s[2]=0,k=3;

    第三次进入DFS函数

    S[3]=5,z=z+1;

    退出第三次进入的DFS函数,返回第二次进入的DFS函数

    I=1,w=1,s[2]=1,k=3

    第三次进入DFS函数

    S[3]=4,z=z+1;

    退出第三次进入的DFS函数,返回第二次进入的DFS函数

    W=0,k=2;

    I=2,w=1,s[2]=2,k=3;

    第三次进入DFS函数

    S[3]=3,z=z+1

    退出第三次进入的DFS函数,返回第二次进入的DFS函数

    !暂停

     

    在此,我们已经得到三组答案数据,即 0 0 5、 0 1 4和 0 2 3

    并且得到Z=3;

    那么按照这个规律,我们可以得出一共会有七组答案数据:

    0 0 7

    0 1 6

    0 2 5

    0 3 4

    1 1 5

    1 2 4

    1 3 3

    2 2 3

     

    在此,我们已经可以利用DFS的方法解决这道题目,当然

    这样解决的效率并不是很高,所有需要剪枝

    优化的代码为:

     1  1 //代码来自西电ACMPPT
     2  2 void dfs(long k, long w)
     3  3 {
     4  4   long i,u;
     5  5   if (k==m)
     6  6     {
     7  7       if (n-w>=s[k-1])
     8  8         {
     9  9           s[k]=n-w;
    10 10           z=z+1;
    11 11         }
    12 12       return;
    13 13     }
    14 14   for (i=0;i<=n;i++)
    15 15     if ((i>=s[k-1])&&((n-w)/(m-k)>=s[k-1]))       //优化剪枝部分
    16 16       {
    17 17         w=w+i;
    18 18         s[k]=i;
    19 19         k=k+1;
    20 20         dfs(k,w);
    21 21         w=w-i;
    22 22         k=k-1;
    23 23       }
    24 24 }
    View Code

    到此为止,本题结束,但是我还想再提一题:

     

    问题 C: 伯努利装错信封问题-综合[难]

    时间限制: 30 Sec  内存限制: 128 MB
    提交: 417  解决: 199
    [提交][状态][讨论版]

    题目描述

        某人写了n封信,同时为每一封信写1个信封,共n个信封。如果把所有的信都装错了信封,问共有多少种?(这是组合数学中有名的错位问题。著名数学家伯努利(Bernoulli)曾最先考虑此题。后来,欧拉对此题产生了兴趣,称此题是“组合理论的一个妙题”,独立地解出了此题)

        

        试编程求出完全装错情形的所有方式及其总量s。例如,输入n=3,即有3封信需要装入信封,完全装错的一种方式可以表示为312,表示第1封信装入第3个信封,第2封信装入第1个信封,第3封信装入第2个信封。对于n=3,完全装错的方式共有2种,分别是312和231.

    输入

    输入一个正整数n(2<=n<=6)

    输出

    输出完全装错情形的所有方式以及装错方式的总量s (每行输出5种方式,一行中的相邻两种方式之间用1个空格隔开。装错方式输出时,从小到大排列,见输出样例)。

    样例输入

    4

    样例输出

    2143 2341 2413 3142 3412

    3421 4123 4312 4321

    s=9

     

    审题思考:

    解决这道题目可以利用DFS。

    参考过百度知道http://zhidao.baidu.com/link?url=RSi7TcgSite5RRMgHhLLGjrF12CdpX9bYL_XvyRkelMC_5HTsZY1lICYgWxNrYBNQ_xKMJWj627uiCHdgDxmYbys8g39Xdf2Bu_ji430GS7

    的回答后,我对代码进行了适当解释和修改,以下是完整代码:

     1 //代码改编自百度知道
     2 #include<stdio.h>
     3 #include<stdlib.h>
     4 int printed,ti=0;
     5 void draw(int* a,int k)//输出函数
     6 {
     7     int i;
     8     for(i=0;i<k;i++)
     9         printf("%d",a[i]);
    10     printf(" ");
    11     if(ti!=5)
    12         ti++;
    13     if(ti==5)
    14     {
    15         printf("
    ");
    16         ti=0;
    17     }
    18 }
    19 void Settle(int *a,int iStep,int k)//函数调用值为:a,0,k
    20 {
    21     int i;
    22     for(i=0;i<iStep-1;i++)
    23         if(a[iStep-1]==a[i]) return;//判断序号为(iStep-1)的信是否同序号为i的信放入同一个信箱,否则将函数返回
    24     if(iStep==k)
    25     {
    26         draw(a,k);
    27         printed++;
    28     }
    29     for(i=1;i<=k;i++)
    30     {
    31         if(i==iStep+1) continue;//判断序号i信是否放到的是i信封,是则继续下一步
    32         a[iStep]=i;
    33         Settle(a,iStep+1,k);
    34     }
    35 }
    36 int main()
    37 {
    38     int* a;
    39     int k;
    40     scanf("%d",&k);
    41     a=(int*)calloc(k,sizeof(int));//在内存的动态存储区中分配k个长度为int大小的连续空间
    42     Settle(a,0,k);
    43     printf("
    s=%d",printed);
    44     return 0;
    45 }

     

      a=(int*)calloc(k,sizeof(int));//在内存的动态存储区中分配k个长度为int大小的连续空间
     /*
         它的意思是a为一块长度为k*sizeof(int) = 4k的内存块,可以存储k个int型变量,这个内存块就相当于一个int数组
     也就是等价于
     int a[k]; // 注意:此时a的内存在堆栈(Stack)上面
     不同的是,你所询问的这句,申请的这块内存区域是动态申请的,属于堆(heap)上面的空间。
     
     calloc是一个C语言函数
       函数名: calloc
       void *calloc(unsigned n,unsigned size);
       功 能: 在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。
       跟malloc的区别:
       calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。
       用 法: void *calloc(unsigned n,unsigned size);
       头文件:stdlib.h或malloc.h
     */

    为了解读这串代码我同样在纸上运行了一小段数据帮助理解

    以下是我在纸上运行的过程:

    以输入N=4 为例

     

    第一次调用settle函数

    a : 空 空 空 空 , istep=0,k=4;

    i=1,i=2,a[0]=2;

    第二次调用settle函数

    a : 2 空 空 空 , istep=1,k=4;

    i=1,a[1]=1

    第三次调用settle函数

    a : 2 1 空 空 , istep=2,k=4;

    i=1,a[2]=1;

    第四次调用settle函数

    a : 2 1 1 空 , istep=3,k=4;

    i=0,i=1,a[1]=a[2]

    函数返回

    第三次调用settle函数

    a : 2 1 空 空 , istep=2,k=4;

    i=2,a[2]=2

    第四次调用settle函数

    a : 2 1 2 空 , istep=3,k=4;

    i=0,a[2]=a[0]

    函数返回

    第三次调用settle函数

    a : 2 1 空 空 , istep=0,k=4;

    ………(省略数步骤)

    第五次调用settle函数

    a : 2 1 4 3 , istep=4,k=4;

    输出2143

     

    经过这样的纸上运行后,发现DFS在编写程序上以递归的形式,可以通过简短的代码解题

    但是面临的问题是:

    1、  代码难写,不好控制终止等条件

    2、  执行效率低(目前我对剪枝的原理还不是很懂)

     

    总结:

    相比于我曾经完全利用的多重FOR循环嵌套语句,DFS递归的方式更体现出了程序的严密和递归的好处

  • 相关阅读:
    整数
    mysql-5.7.13-win32 安装
    Flex air修改外部xml文件 (转)
    JAVA 取得当前目录的路径/Servlet/class/文件路径/web路径/url地址
    C#中&和&&的区别
    百度UEditor1.4.3编辑器和asp.net MVC 5结合
    ASP.NET MVC ajax数组,模型绑定问题。
    MEF依赖注入无法在在构造函数中使用的解决办法
    AJaxFileUpload 文件上传<pre>,json字符串为空解决方法
    C#中字符串转换为IPAdress
  • 原文地址:https://www.cnblogs.com/wushuaiyi/p/3454352.html
Copyright © 2011-2022 走看看