UVa140(带宽)
这道题在写之前一定要把题目读懂,笔者在设计代码时就对题意产生了错误的理解,好在后来这个错误被纠正了。
这道题最主要的点就是对解答树遍历并且回溯,也就是《算法竞赛入门经典》中所提到的“剪枝”。递归的主体是生成结点的全排列,而回溯操作简单来说就是在这个递归的基础上添加的一个判断。
先说生成全排列递归的操作,生成全排列就是在现有数组的基础上对数组进行新元素的插入,每次插入都会对已有数组进行遍历,如果发现新插入的元素在前面的数组中已经出现过,那么就跳过剩余操作插入下一个元素,递归的结束条件就是当前数组的长度与给出数组的长度相同。
再说回溯操作,程序中添加了一个变量MINB来记录当前所有排列中最小的带宽,每当数组中新添加了一个元素,就计算该元素(结点)与它相邻的结点的距离,如果此距离超过了最小带宽,那么就不用再遍历下去了,直接回溯。
需要提到的是,程序中图是使用邻接矩阵存储的,不过在把代码写完后,笔者发现或许使用邻接表存储会更加方便。
1 #include
2
3 using namespace std;
4
5 /****************
6 UVa140(带宽)
7 ***************/
8
9 const int MAX = 8;
10
11 int node[MAX];
12 //用来记录带宽最小的结点序列
13 int minB[MAX];
14 //邻接矩阵
15 int buf[MAX][MAX];
16 int MAXL = 0;//带宽
17 int MINB = 99999;//最小带宽
18
19 //该函数是求排列的带宽的
20 //n:结点个数(字符数组长度)
21 //cur:当前位置
22 int BandWidth(int n){
23 int cur = 0, i = 0, bnw = 0,j;
24 while(i < n && cur < n){
25 int k = node[cur];
26 //寻找相邻结点
27 if(buf[k][i]){
28 for(j = 0; j < n; j++){
29 //在结点序列中寻找相邻结点
30 if(node[j] == i){
31 bnw = max(abs(j-cur), bnw);
32 }
33 }
34 }
35 //某个结点遍历结束
36 if(i == n-1){
37 i = 0;
38 cur++;
39 continue;
40 }
41 i++;
42 }
43 return bnw;
44 }
45
46 void solve(int n, int cur)
47 {
48 if(cur == n){
49 MAXL = BandWidth(n);
50 if(MINB > MAXL){
51 for(int i = 0; i < n; i++){
52 minB[i] = node[i];
53 }
54 MINB = MAXL;
55 }
56 }
57 else{
58 for(int i = 0; i < n; i++){
59 int ok = 1;
60 for(int j = 0; j < cur; j++)
61 if(node[j] == i) ok = 0;
62 if(ok){
63 int tmp = 0;
64 //寻找相邻结点
65 for(int j = 0; j < n; j++){
66 if(buf[i][j]){
67 //遍历当前数组有没有相邻结点
68 for(int k = 0; k < cur; k++)
69 if(node[k] == j)
70 tmp = MINB - (cur - k);
71 }
72 if(tmp < 0) return;
73 }
74 node[cur] = i;
75 solve(n, cur+1);
76 }
77 }
78 }
79
80 }
81
82 int main()
83 {
84 //n:结点数
85 int n = 0;
86 cin >> n;
87 //x,y是边的两条结点
88 char x, y;
89 memset(buf, 0, sizeof(buf));
90 //构建邻接矩阵
91 while(true){
92 cin >> x;
93 cin >> y;
94 if(x == '#' && y == '#') break;
95 buf[x-65][y-65] = 1;
96 buf[y-65][x-65] = 1;
97 }
98 solve(n, 0);
99 //输出结果
100 for(int i = 0; i < n; i++){
101 printf("%c", minB[i]+65);
102 }
103 printf("\n");
104 printf("%d", MINB);
105 return 0;
106 }
在编写代码时觉得代码还不够精简,或许还有优化空间。
运行结果为:
8
A B
A F
B C
B G
C D
D E
D G
E H
F G
F H
# #
ABCFGDHE
3