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 }
原文地址:https://www.cnblogs.com/firstrate/p/3223105.html