代码改变世界

uva 129 回溯法入门

2015-02-14 21:12  KI@#  阅读(729)  评论(0)    收藏  举报

题意:给出n,l;要求按特定格式输出由前l个大写字母构成的按字母表排列的第n个没有连续重复子串的字符串以及该字符串长度。

1、避免相邻的重复子串:生成字符串方式为逐个在后面添加字符,只要每次在添加字符后检查与新添加的字符相关的字符串时候满足条件即可。

2、要求按字母表顺序生成子串:从A开始,逐个向后生成。每次添加字母后若满足条件,继续从A开始添加字母;若不满足条件,返回上一级(回溯)。

3、生成的子串数达到给定的数量n后,退出程序(若调用的函数有返回值,则返回特定值0,或1)。

 

 1 #include <cstdio>
 2 
 3 int S[100];
 4 int n, L, cnt;//cnt记录已经生成的合法字符串的个数 
 5 
 6 int dfs(int cur)//cur记录S此时对应的字符串的长度 
 7 {
 8     if(cnt++ == n)//完成搜索,输出结果并逐级结束函数调用 (返回0)
 9     {
10         for(int i = 0; i < cur; ++i)
11         {
12             if(i % 64 == 0 && i) printf("\n");
13             else if(i % 4 == 0 && i) printf(" ");
14             printf("%c", 'A' + S[i]);
15         }//特定格式输出 
16         printf("\n%d\n", cur);
17         return 0;//函数调用结束 
18     }
19     for(int i = 0; i < L; ++i)//i从0开始,'A'+s[cur]从A开始 
20     {
21         S[cur] = i;
22         int ok = 1;
23         for(int j = 1; j*2 <= cur + 1; ++j)//从j为1开始检查所有含有尾字母的相邻子串是否满足条件 
24         {
25             int equal = 1;
26             for(int k = 0; k < j; ++k) 
27                 if(S[cur-k] != S[cur-k-j]) { equal = 0; break; }
28             if(equal) { ok = 0; break; }
29         }
30         if(ok) if(!dfs(cur+1)) return 0;//这里函数调用时参数为cur+1而不是cur++:在特定层次cur值固定 
31     }
32     return 1;//回溯 ——返回上一级 
33 }
34 
35 int main()
36 {
37     while(scanf("%d%d", &n, &L) == 2 && n)
38     {
39         cnt = 0;//已找到合法字符串0个 
40         dfs(0);//开始时S数组对应的字符串长度为0 
41     }
42     return 0;
43 }
View Code


注:简单的函数调用过程描述:

顺序执行,遇到子过程后,先保存当前状态后调用,执行完之后再返回