給出一個圖,找出其中的最小帶寬的排列。具體要求見傳送門:UVa140
這題有些小技巧可以簡化代碼的編寫。
本題的實現參考了劉汝佳老師的源碼,的確給了我許多啟發,感謝劉老師。
思路:
- 建立雙射關系:從字符A到字符Z遍歷輸入的字符串,用strchr函數將輸入中出現的字符找出,並將找出的字符進行編號,用letter和id分別存儲字符和對應的編號
- 降維:輸入中給出的,是類似於鄰接表形式的二維形式,如果我們用二維數據結構,將增加處理時對於輸出細節的處理難度,用 2個 vector將輸出降低到1維,簡化了計算Bandwidth時的代碼,實際上讓我們更加有的放矢
- 存儲必要信息——位置:數組pos每個下標代表字母編號,存儲的是對應的位置下標,便於計算時尋找位置。
- 剪枝:減去不必要的計算(雖然對於本題而言不是必須的)
- 庫函數的使用:memcpy,strchr,strlen,next_permutation的使用簡化了代碼,突出了邏輯部分。
代碼實現如下:
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 using namespace std; 6 7 const int maxn=10,inf=0x7fffffff; 8 char letter[maxn], s[100];//字母,輸入序列 9 int id[256]; //字母的編號 10 int p[maxn]; //全排列的遍歷數組 ,存儲的是每個字母的編號 11 int pos[maxn];//記錄每個字母的位置,避免頻繁使用strchr 12 13 int main(){ 14 while(scanf(" %s",&s),s[0]!='#'){ 15 int len=strlen(s),n=0; 16 for(char ch='A';ch<='Z';ch++)if(strchr(s,ch)!=NULL){ 17 letter[n]=ch; 18 id[ch]=n++; 19 } 20 vector<int> u,v; 21 for(int i=0;i<len;i++){ 22 int t=i;//記錄起始節點 23 i+=2; 24 while(i<len && s[i]!=';'){ 25 u.push_back(id[s[t]]);//加入起始節點 26 v.push_back(id[s[i]]);//加入起始節點的相鄰節點 27 i++; 28 } 29 } 30 //遍歷+剪枝 31 int bandwidth=0,res=inf; 32 int bestP[maxn];//存儲最終結果 33 for(int i=0;i<n;i++)p[i]=i; 34 do{ 35 bandwidth=0;//初始化別忘了 36 for(int i=0;i<n;i++)pos[p[i]]=i;//記錄編號為pi的節點的位置 37 for(int i=0;i<u.size();i++){ 38 bandwidth=max(bandwidth,abs(pos[u[i]]-pos[v[i]])); 39 if(bandwidth>=res)break;//剪枝 40 } 41 if(bandwidth<res){ 42 memcpy(bestP,p,sizeof(p));//memcpy比較快 43 res=bandwidth; 44 } 45 }while(next_permutation(p,p+n)); 46 for(int i=0;i<n;i++)printf("%c ",letter[bestP[i]]); 47 printf("-> %d\n",res); 48 } 49 }