UVa140(帶寬)

這道題在寫以前必定要把題目讀懂,筆者在設計代碼時就對題意產生了錯誤的理解,好在後來這個錯誤被糾正了。node

這道題最主要的點就是對解答樹遍歷而且回溯,也就是《算法競賽入門經典》中所提到的「剪枝」。遞歸的主體是生成結點的全排列,而回溯操做簡單來講就是在這個遞歸的基礎上添加的一個判斷。c++

先說生成全排列遞歸的操做,生成全排列就是在現有數組的基礎上對數組進行新元素的插入,每次插入都會對已有數組進行遍歷,若是發現新插入的元素在前面的數組中已經出現過,那麼就跳過剩餘操做插入下一個元素,遞歸的結束條件就是當前數組的長度與給出數組的長度相同。算法

再說回溯操做,程序中添加了一個變量MINB來記錄當前全部排列中最小的帶寬,每當數組中新添加了一個元素,就計算該元素(結點)與它相鄰的結點的距離,若是此距離超過了最小帶寬,那麼就不用再遍歷下去了,直接回溯。數組

須要提到的是,程序中圖是使用鄰接矩陣存儲的,不過在把代碼寫完後,筆者發現或許使用鄰接表存儲會更加方便。函數

 1 #include <bits/stdc++.h>
 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 } 

在編寫代碼時以爲代碼還不夠精簡,或許還有優化空間。優化

運行結果爲:spa

8 A B A F B C B G C D D E D G E H F G F H # # ABCFGDHE 3
相關文章
相關標籤/搜索