7.29 DFS总结

来源:互联网 发布:数据库验收要求 编辑:程序博客网 时间:2024/05/21 18:33

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("\n");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\n",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\n", 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,就更新min33         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\n", 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\n", 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     else26     {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("\n");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 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 0
原创粉丝点击