zoukankan      html  css  js  c++  java
  • 7.29 DFS总结

    7.29   黄昏时刻

    (一) 全排列

    建模:

      给了数字n 代表从1-n 个数全排列

    思路:

      1. 输入n,如果n值为‘0’,则退出程序
      2. vis[i] 保存 是否对第i个数字进行访问
      3. dfs 遍历1-n 个数字的全排列,若重复访问,则越过。直到最终访问结束输出访问的的结果。之后回溯删掉对数字的访问。

    优化:
      none

    代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 int a[20] ,n, vis[20];
     5 
     6 void dfs(int s) {
     7     int i;
     8     //如果dfs 次数为n,则输出a数组的内容
     9     if(s == n) {
    10         for(i = 0; i < n; i++)
    11             printf("%-5d", a[i]); // -5 是格式化输出左对齐
    12         printf("
    ");
    13         return;
    14     }
    15     //遍历 1- n  如果访问过则继续循环呗
    16     for(i = 1; i <= n; i++) {
    17 
    18         if(vis[i]) continue;
    19         vis[i] = 1;      //标记节点被访问过
    20         a[s] = i;      //在a 数组存取全排列的数字
    21         dfs(s+1);      //深搜
    22         vis[i] = 0;   //回溯操作,删掉节点访问痕迹
    23     }
    24 }
    25 
    26 
    27 int main() {
    28     while(1) {
    29         scanf("%d", &n);
    30         if(!n) break;
    31         memset(vis, 0, sizeof(vis));
    32         dfs(0);
    33     }
    34     return 0;
    35 }

    (二)全组合

    建模:

      给了数值n 对n 进行组合,并打印出。

    思路:

      1.输入n , 如果n不存在 返回。
      2.dfs 找出n个数字的组合,用‘0’,‘1’标记法判断一个数字是否存在,并且对存在或者不存在依次进行递归。
      3.若dfs次数>n,则输出组合的结果。

    代码:

     1 #include <stdio.h>
     2 
     3 int n, a[20];
     4 
     5 void dfs(int s) {
     6     int i;
     7     //输出排列后的结果
     8     if(s > n) {
     9         for(i = 1; i <= n; i++) {
    10             if(a[i]) 
    11                 printf("%-5d ", i);  
    12         }
    13         return;
    14     }
    15     //对a[s]的存在亦或是不存在的两种情况进行递归。
    16     a[s] = 0;
    17     dfs(s+1);
    18     a[s] = 1;
    19     dfs(s+1);
    20 }
    21 
    22 int main() {
    23 
    24     while(1) {
    25         scanf("%d", &n);
    26         if(!n) break;
    27         dfs(1);
    28     }
    29 
    30     return 0;
    31 }

      

     (D89) The settlers of catan

    建模:

      已知n 个点,m 条边,输入两个点来构成一条边,构成一副无向图,两点之间可以有多条边,从任意一个点搜索,要求每条边只能经过一次,找到最长的路径。

    思路:

      1.输入点的个数n, 边的个数m,并且初始化存整个无向图的二维数组w
      2.存边进入二维数组W
      3.对所有点进行dfs搜索,如果路径最长则更新max
      4.dfs找出所有存在的边,并且记录路径的长度

    代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 #define N 26
     4  
     5 int w[N][N],max,n;  //w[N][N] 存入整个图,w[i][j]=x 代表i到j有x条边
     6  
     7 void dfs(int,int);
     8  
     9 int main()
    10 {
    11     int m,sum;
    12     int a,b,i;
    13     while(1)
    14     {        
    15         scanf("%d%d",&n,&m);
    16         if(!m && !n)
    17             break;
    18  
    19         memset(w,0,sizeof(w)); //初始化
    20  
    21         for(i=0;i<m;i++)
    22         {
    23             scanf("%d%d",&a,&b);
    24             w[a][b]++;  //无向图
    25             w[b][a]++;
    26         }
    27  
    28         max=0; 
    29         for(i=0;i<n;i++)
    30         {
    31             sum=0;   //把每个点作为出发点,对每一个点进行搜索
    32             dfs(i,sum);
    33         }
    34         printf("%d
    ",max);
    35     }
    36     return 0;
    37 }
    38  
    39 void dfs(int a,int sum)  // a 为当前探索到哪一个节点,sum为当前探索到的路径长度
    40 {
    41     int i;
    42     if(sum>max)  //更新当前搜索到的最长路径
    43         max=sum;
    44     for(i=0;i<n;i++)
    45     {
    46         if(w[a][i])
    47         {
    48             w[a][i]--;  w[i][a]--; //用去一条边
    49             dfs(i,sum+1);  // 进行下一层递归
    50             w[a][i]++;  w[i][a]++; //回溯到上一层
    51  
    52         }
    53     }
    54     return;
    55 }

    (A38) A long stick 

    建模:

      给了n个棍子的长度, 和b的值
      找出一些棍子链接起来得到长度length, length >= b, length尽量接近b

    思路:

      1. min为结果, 初始化为所有棍子的长度和。
      2. dfs找出这堆棍子的组合, 判断每一种组合所得到的长度sum, sum与min相比, 如果sum比min更优, 更新min为sum

    优化:

      1. 剪枝
        a) 在当前搜索到的状态下, 假设剩下的棍子全部装完, 得到的结果 < b, 则可以剪枝.
        b) 当搜索到的sum >= b时, 判断sum 与 min, 然后剪枝
      2. 排序, 将棍子长度逆序排序, 在搜索的过程中, sum的增长速度会更快, 也可以提高剪枝效率。

    未优化的代码:

     1 #include <stdio.h>
     2  
     3 int n, b;
     4 int len[28];
     5 int min;
     6  
     7 void dfs(int ,int);
     8  
     9 int main() {
    10     int t, i;
    11     scanf("%d", &t);//输入t次后结束
    12     while(t--) {
    13  
    14         scanf("%d%d", &n, &b);//n为小棍子数目,b为拼接后的长度最接近的值
    15         min = 0;//拼接后趋近的结果
    16         for(i = 0; i < n; i++) {//输入n组小棍子长度
    17             scanf("%d", &len[i]);
    18             min += len[i];
    19         }
    20  
    21         dfs(0,0);//递归求最接近b长度的若干根棍子合起来的长度值
    22         printf("%d
    ", min);//输出结果
    23     }
    24  
    25     return 0;
    26 }
    27 
    28 void dfs(int sum, int i) {
    29     
    30     if(min == b) //假如拼接后的长度min 刚好为b 则返回
    31         return;
    32     if(sum >= b) {//如果棍子拼接的长度刚好>=b 如果比之前拼接的长度更接近于b,就更新min
    33         if(sum < min) 
    34             min = sum;
    35         return;
    36     }
    37     if(i == n) return;//避免死递归判断假如存在n的情况
    38     dfs(sum+len[i], i+1);//如果存在第i根棍子,往下搜索求和
    39     dfs(sum, i+1);//假设不存在第i根棍子,继续搜索求和
    40 }

    剪枝后的优化:

     1 #include <stdio.h>
     2 #include <string.h>
     3  
     4 int n, b;
     5 int len[28], s[28];
     6 int min;
     7  
     8 void dfs(int sum, int i);
     9  
    10 int main() {
    11     int t, i;
    12     scanf("%d", &t);
    13     while(t--) {
    14  
    15         scanf("%d%d", &n, &b);
    16         min = 0;
    17         memset(s, 0, sizeof(s));
    18         for(i = 0; i < n; i++) {
    19             scanf("%d", &len[i]);
    20             min += len[i];
    21         }
    22         for(i = n-1; i > -1; i--) //记录最后一根棍子 to 第i根棍子 的总长度
    23             s[i] = s[i+1] + len[i];
    24  
    25         dfs(0,0);
    26         printf("%d
    ", min);
    27     }
    28     return 0;
    29 }
    30 
    31 void dfs(int sum, int i) {
    32     if(min == b) 
    33         return;
    34     if(sum >= b) {
    35         if(sum < min) 
    36             min = sum;
    37         return;
    38     }
    39     if(i == n) return;
    40     if(sum+len[i]+s[i+1] >= b ) //剪枝 
    41         dfs(sum+len[i], i+1);
    42     if(sum+s[i+1] >= b) //剪枝
    43         dfs(sum, i+1);
    44  
    45 }

    剪枝排序后的优化:

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4  
     5 int n, b;
     6 int len[28], s[28];
     7 int min;
     8  
     9 void dfs(int sum, int i);
    10 
    11 int cmp(const void *a,const void *b)
    12 {
    13     return *(int *)b-*(int*)a;
    14 }
    15 
    16 
    17  
    18 int main() {
    19     int t, i;
    20     scanf("%d", &t);
    21     while(t--) {
    22  
    23         scanf("%d%d", &n, &b);
    24         min = 0;
    25         memset(s, 0, sizeof(s));
    26         for(i = 0; i < n; i++) {
    27             scanf("%d", &len[i]);
    28             min += len[i];
    29         }
    30 
    31         qsort(len,n,sizeof(len[0]),cmp);
    32 
    33 
    34         for(i = n-1; i > -1; i--) //记录最后一根棍子 to 第i根棍子 的总长度
    35             s[i] = s[i+1] + len[i];
    36  
    37         dfs(0,0);
    38         printf("%d
    ", min);
    39     }
    40     return 0;
    41 }
    42 
    43 void dfs(int sum, int i) {
    44     if(min == b) 
    45         return;
    46     if(sum >= b) {
    47         if(sum < min) 
    48             min = sum;
    49         return;
    50     }
    51     if(i == n) return;
    52     if(sum+len[i]+s[i+1] >= b ) //剪枝 
    53         dfs(sum+len[i], i+1);
    54     if(sum+s[i+1] >= b) //剪枝
    55         dfs(sum, i+1);
    56  
    57 }

     

    DFS 题目  用到的DFS函数:

     1 // The Settlers of Catan    V1
     2 
     3 void dfs(int a,int sum) 
     4 {
     5     int i;
     6     if(sum>max)  max=sum;
     7     for(i=0;i<n;i++)
     8     
     9         if(w[a][i]){
    10             w[a][i]--;  w[i][a]--; 
    11             dfs(i,sum+1); 
    12             w[a][i]++;  w[i][a]++; 
    13         }
    14     
    15     return;
    16 }
     1 // The Settlers of Catan V2
     2 
     3 void dfs(int u, int num){
     4   int flag;
     5     for(int v=0; v<n; ++v){
     6         if(G[u][v] && !vis[u][v]){
     7  
     8             if(G[u][v] != 1){
     9                 flag = 1;
    10                 vis[u][v] = 0;
    11                 vis[u][v] = 0;
    12                 G[u][v] --; 
    13                 G[v][u] --;
    14             }
    15             else {
    16                 vis[u][v] = 1;
    17                 vis[v][u] = 1;
    18          
    19             }
    20          
    21             dfs(v, num+1);
    22             if(flag == 1){
    23                 G[u][v]++;
    24                 G[v][u]++;
    25             }
    26             flag = 0;
    27             vis[u][v] = vis[v][u] = 0;
    28         }
    29     }
    30  
    31     if(num > maxNum) maxNum = num;
    32 }
     1 // A long stick
     2 
     3 void dfs(int sum,int i)
     4 {
     5     int j;
     6     sum-=stick[i];
     7     if(sum<length || min==length)
     8         return;
     9  
    10     if(sum<min)
    11         min=sum;
    12  
    13     for(j=i+1;j<=n;j++)
    14         dfs(sum,j);
    15 }
     1 // repeatless   V1
     2 
     3 void dfs(int dep)
     4 {
     5     int i;
     6     if (dep==10)
     7     {
     8         int tmp=d[1];
     9         for (i=2;i<=10;i++) tmp=tmp*10+d[i];
    10         T++;
    11         f[T]=tmp;
    12         return;
    13     }
    14     if (T>1000010) return;
    15     for (i=0;i<=9;i++)
    16         if (s[i]==0)
    17         {
    18             d[dep+1]=i;
    19             sum+=i;
    20             if (sum) s[i]++;
    21             dfs(dep+1);
    22             if (sum) s[i]--;
    23             sum-=i;
    24         }
    25 }
     1 // repeatless   V2    author : ZSX
     2 
     3 void recursion( int k )
     4 {
     5     if( bl == 0 ) 
     6         return ;
     7     int i, j;
     8     int a, b;
     9     if( p == k )
    10     {
    11         int sum = 0;
    12         int temp;
    13         for( i=0; i<p; i++ )
    14         {
    15             temp = 1;
    16             for( j=0; j<p-i-1; j++ )
    17                 temp *= 10;
    18             sum += temp*buffer[i];
    19         }
    20         if( q <= 1000000)
    21             array[q++] = sum;
    22         else  
    23             bl = 0;
    24     }
    25     else
    26     {
    27         for( a=0; a<=9; a++ )
    28             if( flag[a] == 0 && (p != 0 || a!=0) )
    29             {
    30                 flag[a] = 1;
    31                 buffer[p++] = a;
    32                 recursion( k );
    33                 flag[a] = 0;
    34                 p--;
    35             }
    36     }
    37 }
     1 // 全排列
     2 
     3 void dfs(int s, int n) {
     4     int i;
     5     if(s == n) {
     6         for(i = 0; i < n; i++)
     7             if(i==0) printf("%d", a[i]);
     8             else     printf(" %d", a[i]);
     9         printf("
    ");
    10         return;
    11     }
    12     for(i = 1; i <= n; i++) {
    13         if(vis[i]) continue;
    14         a[s] = i;
    15         vis[i] = 1;
    16         dfs(s+1, n);
    17         vis[i] = 0;
    18     }
    19 }
  • 相关阅读:
    3.18日
    线程的面试题
    关于instanceof测试遇到的问题
    spring
    自动登录代码
    Filter
    多态
    基于HTML,css,jQuery,JavaScript,MySQL搭建博客系统
    基于bootstrap+MySQL搭建动态网站
    基于bootstrap_网站汇总页面
  • 原文地址:https://www.cnblogs.com/firstrate/p/3223105.html
Copyright © 2011-2022 走看看