题目大意:求一个使带宽最小的排列和最小带宽。带宽是指一个字母到其相邻字母的距离最大值。
题目分析:在递归生成全排列的过程中剪枝,剪枝方案还是两个。一、当前解不如最优解优时,减去;二、预测的理想解不必最优解优时,减去。将与当前最后一个位置上的字母相邻的字母全部接过来,便得理想解。
代码如下:
# include<iostream> # include<cstdio> # include<string> # include<vector> # include<cstring> # include<algorithm> using namespace std; char p[100]; vector<int>v[30],w; int ans,vis[30],n; string ansp; void init() { int l=strlen(p); int now; for(int i=1;i<l;++i){ if(p[i]==';') continue; if(p[i]==':'){ now=p[i-1]-'A'; continue; } if(p[i-1]!=';'){ vector<int>::iterator it; it=find(v[now].begin(),v[now].end(),p[i]-'A'); if(it==v[now].end()) v[now].push_back(p[i]-'A'); it=find(v[p[i]-'A'].begin(),v[p[i]-'A'].end(),now); if(it==v[p[i]-'A'].end()) v[p[i]-'A'].push_back(now); } } for(int i=0;i<30;++i) sort(v[i].begin(),v[i].end()); w.clear(); vector<int>::iterator it; for(int i=0;i<l;++i){ if(p[i]==':'||p[i]==';') continue; it=find(w.begin(),w.end(),p[i]-'A'); if(it==w.end()) w.push_back(p[i]-'A'); } sort(w.begin(),w.end()); n=w.size(); } int f(string app,int g,int pos) { for(int i=0;i<app.size();++i){ if(i==pos) continue; if(app[i]==g+'A') return i; } return pos; } int get(string app) { int res=0; int l=app.size(); for(int i=0;i<l;++i){ for(int j=0;j<v[app[i]-'A'].size();++j){ int pos=f(app,v[app[i]-'A'][j],i); res=max(res,abs(pos-i)); } } return res; } void dfs(int cur,int now,string ap) { if(cur==n){ if(now<ans){ ans=now; ansp=ap; } return ; } if(now>=ans) return ; int l=ap.size(); if(l>0){ string app=ap; for(int i=0;i<v[ap[l-1]-'A'].size();++i){ int j; for(j=0;j<l;++j) if(v[ap[l-1]-'A'][i]==ap[j]-'A') break; if(j>=l) app+=char(v[ap[l-1]-'A'][i]+'A'); } if(get(app)>=ans) return ; } for(int i=0;i<n;++i){ if(vis[w[i]]) continue; vis[w[i]]=1; dfs(cur+1,get(ap+char(w[i]+'A')),ap+char(w[i]+'A')); vis[w[i]]=0; } } int main() { while(scanf("%s",p)) { if(p[0]=='#') break; for(int i=0;i<30;++i) v[i].clear(); init(); ans=100; ansp.clear(); memset(vis,0,sizeof(vis)); dfs(0,0,""); int len=ansp.size(); for(int i=0;i<len;++i) printf("%c ",ansp[i]); printf("-> %d ",ans); } return 0; }