一般认为,回溯法嘛,当然剪枝剪的越多越好了。
但是有时候,如果剪枝所使用的判断方式十分繁琐的话,有时候不如不剪这个枝,而只抓住哪些容易剪的,对结果影响大的来剪枝。
这道题就是个很好的例子:
这道题的思路是这样的,枚举全排列,然后计算其带宽,在枚举全排列的时候,可以剪枝。
在枚举非可重集的全排列的基础上,还可以再去剪枝,主要有两种剪枝的方式:
第一种是:每放置一步,就判断这一步放置的字符的最大带宽是否大于之前已经计算好的带宽,如果大于,则剪枝
第二种是:放置完一个字符以后,如果与这个字符相邻的点还有m个,那么最小的带宽也是m,如果m比之前已经计算好的带宽大的话,剪枝
上面两种剪枝方式都可以,但是编程还是比较的繁琐的。
所以要在时间效率和编程复杂度之间进行权衡
从这道题中学到的东西有:
字符的处理方式,保存的时候,就直接-‘A’,而不要每次使用的时候都减'A'
不需要太纠结图的存储方式,因为在边特别多的时候,无论哪种存储方式,数据结构对时间的影响是很小的,所以,如果有有限个点,那么一般使用数组,其它情况可以使用vector
只需要处理边的时候,遍历半张图就可以了
下面附上AC代码,剪枝的版本以后有时间再回来思考
//对于这道题,我目前的思路是使用vector保存图,使用一个seq数组来保存排列 //seq[i]代表字母'A' + i 在排列中的顺序 //然后枚举排列一个一个计算 //我之前想不能够剪枝的原因是,我觉得只有把所有的排列都枚举出来以后才可以开始计算带宽 //但实际上不是这样的,只算出排列的前几个,也可以计算出部分的带宽()这样的话数据结构就应该使用数组,来保存图,而不是vector,因为它的比较使用的不是遍历,而是直接判断 //所以可以用两个条件来剪枝,第一个就是计算已经排好了的节点的带宽,如果排好了的里面的带宽的最大值大于之前已经找到的最小值,那么剪枝 //第二个就是使用没有排好的,当排一个节点的时候,如果这个节点发现还有m个它的节点没有排,那么这个节点和没有排的相邻节点的带宽至少为m,如果m比之前找到的 //最小值要大,那么剪枝 //综上所述:使用的数据结构有 //vis[max],G[maxn][maxn],cnt[maxn],,vis用来排排列,G[][]用来第一次剪枝,cnt用来第二次剪枝 #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<set> using namespace std; const int maxn = 30; int vis[maxn]; int G[maxn][maxn]; int seq[maxn]; int best_seq[maxn]; set<int>node; vector<int>exist; int max_bandwith; void print_G() { for(int i = 0;i < 8;i++) { for(int j = 0;j < 8;j++) { printf("%d ",G[i][j]); } printf("\n"); } printf("\n"); } bool read_input() { int x; memset(vis,0,sizeof(vis)); memset(G,0,sizeof(G)); node.clear(); exist.clear(); for(;;) { x = getchar(); if(x == '#') return false; if(!node.count(x)) { node.insert(x); } for(;;) { int y = getchar(); if(y == '\n') { for(set<int>::iterator it = node.begin();it != node.end();it++) { exist.push_back(*it - 'A'); } return true; } else if(y == ':') continue; else if(y == ';') break; else { if(!node.count(y)) { node.insert(y); } G[x - 'A'][y - 'A'] = G[y - 'A'][x - 'A'] = 1; } } } } void compute() { int bandwith = 0; for(int i = 0;i < 26;i++) { for(int j = i;j < 26;j++) { if(G[i][j]) { bandwith = max(bandwith,abs(seq[i] - seq[j])); } } } if(bandwith < max_bandwith) { max_bandwith = bandwith; for(int i = 0;i < exist.size();i++) { best_seq[seq[exist[i]]] = exist[i]; } } } void print_seq() { for(int i = 0;i < exist.size() ;i++) { printf("%d ",seq[exist[i]]); } printf("\n"); } void dfs(int cur) { if(cur == node.size()) { //print_seq(); compute(); return; } else { for(int i = 0;i < exist.size();i++) { if(!vis[i]) { seq[exist[cur]] = i; vis[i] = 1; dfs(cur + 1); vis[i] = 0; } } } } int main() { #ifdef local freopen("input.txt","r",stdin); #endif while(read_input()) { //print_G(); max_bandwith = 26; dfs(0); for(int i = 0;i < exist.size();i++) { if(i) printf(" "); printf("%c",best_seq[i] + 'A'); } printf(" -> %d\n",max_bandwith); } return 0; }