7.29 黄昏时刻
(一) 全排列
建模:
给了数字n 代表从1-n 个数全排列
思路:
1. 输入n,如果n值为‘0’,则退出程序
2. vis[i] 保存 是否对第i个数字进行访问 3. dfs 遍历1-n 个数字的全排列,若重复访问,则越过。直到最终访问结束输出访问的的结果。之后回溯删掉对数字的访问。优化:
none
代码:
1 #include2 #include 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 #include2 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 #include2 #include 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 max) //更新当前搜索到的最长路径43 max=sum;44 for(i=0;i
(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 #include2 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 #include2 #include 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 #include2 #include 3 #include 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
1 // The Settlers of Catan V2 2 3 void dfs(int u, int num){ 4 int flag; 5 for(int v=0; vmaxNum) 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
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
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 }