UVA 140 Bandwidth (dfs 剪枝 映射)

题意:

给定一个n个结点的图G和一个结点的排列, 定义结点i的带宽b(i)为i和相邻结点在排列中的最远距离, 所有b(i)的最大值就是这个图的带宽, 给定G, 求让带宽最小的结点排列。

给定的图 n <=8, 字母包含A~Z

上图是两种排列, 图1 各个b(i) 为 6 6 1 4 1 1 6 6 最大值为6  图2 b(i)为 5 3 1 4 3 5 1 4 最大值为 5

本图答案应为 A B C F G D H E    

b(i)为3  3  3  3  2  3  3  3, 最大值为3.

分析:

首先本题输入格式是那种给出一行,然后比较繁琐的题目, 所以可以考虑先读入一行再进行处理会比边读边处理好一点。

读入后第一要确认的就是这个图包含哪些字母, 因为本题需要全排列并按字典序输出, 所以最好把字母先映射为id, 这里使用了,strchr(const char* , char), 该函数可返回字符串中char第一次出现的位置, 不包含该ch则返回NULL。

并把编号由大到小写到letter中, 那么只需要生成这些id的全排列, 就能知道这些字母的全排列。

第二步是建图, 把输入中有用的信息提炼出来, 那么就可以用邻接矩阵建图了,不使用邻接表是因为本题输入会有重边。

然后就可以dfs生成全排列了, 这里我只用了一个剪枝, 就是搜索到结点u时, 如果u有m个相邻结点,而且有last(m-已经选中的结点)个还没被我前面的递归选中, 那么如果last > 当前最优带宽k, 就可以剪枝。 因为对于结点u而言, 最理想情况是这last个结点紧跟在u后, 这样结点带宽为m, 如果m >= 目前已经找到最优带宽k , 剪枝是合理的。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 char input[3000];
 4 int id[256], letter[30], node[30], temp[30], best_wid[30];
 5 int adj[10][10];
 6 int cnt = 0;
 7 int min_wid = 1e5;
 8 bool vis[30];
 9 int pos[30];
10 void dfs(int dep){
11     if(dep == cnt){
12         int t_wid = -1, pp_wid = -1;
13         for(int i = 0; i < cnt; i++){
14             pp_wid = -1;
15             for(int j = 0; j < cnt; j++){
16             if(adj[i][j]){
17                     pp_wid = max(pp_wid, abs(pos[i] - pos[j]) );
18                 }
19             }
20             t_wid = max(t_wid, pp_wid);
21         }
22         if(t_wid < min_wid){
23             for(int i = 0; i < cnt; i++){
24                 best_wid[i] = temp[i];
25             }
26             min_wid = t_wid;
27         }
28     }
29     else{
30         for(int i = 0; i < cnt; i++){
31             if(!vis[i]){
32                 int last = 0;
33                 for(int j = 0; j < cnt; j++)
34                 {
35                     if(adj[i][j]){
36                         int ok = 1;
37                         for(int k = 0; k < dep; k++){
38                             if(temp[k] == j) { ok = 0; break;}
39                         }
40                         if(ok) last ++;
41                     }
42                 }
43                 if(last >= min_wid)
44                     continue;
45                 vis[i] = 1;
46                 temp[dep] = i;
47                 pos[temp[dep]] = dep;
48                 dfs(dep+1);
49                 vis[i] = 0;
50             }
51         }
52     }
53 }
54 int main()
55 {
56     while(scanf("%s", input) && input[0] != '#'){
57         memset(adj,0,sizeof(adj));
58         cnt = 0,  min_wid = 1e5;
59         for(char a = 'A'; a <= 'Z'; a++){
60             if(strchr(input, a)){
61                 id[a] = cnt++;
62                 letter[id[a]] = a;
63             }
64         }
65         int len = strlen(input), p=0, q=0;
66         while(1){
67             while(p < len && input[p]!= ':')
68                 p++;
69             if(p == len) break;
70             while(q < len && input[q]!= ';')
71                 q++;
72 //             p定位: q定位;
73             for(int i = p+1; i < q; i++){
74                 adj[id[input[p-1]]][id[input[i]]] = 1;
75                 adj[id[input[i]]][id[input[p-1]]] = 1;
76             }
77             p++, q++;
78         }
79 
80         dfs(0);
81         for(int i = 0; i < cnt; i++){
82             printf("%c ", letter[best_wid[i]]);
83         }
84         printf("-> %d
", min_wid);
85     }
86     return 0;
87 }
原文地址:https://www.cnblogs.com/Jadon97/p/7155717.html