题意:
给定一个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 #include2 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\n", min_wid); 85 } 86 return 0; 87 }