Uva140 Bandwidth 全排列+生成测试法+剪枝

参考过仰望高端玩家的小清新的代码。。。

思路:1.按字典序对输入的字符串抽取字符,id[字母]=编号,id[编号]=字母,形成双射

      2.邻接表用两个vector存储,存储相邻关系

      3.先尝试字母编号字典序最小的排列,此为next_permutation的最上排列

      4.在最理想的情况下都不能得到比当前最优解更好的方案,则应当剪枝(prune)

      5.memcpy(),strchr()方法来自于库函数

测试集:

Input:

     A:FB;B:GC;D:GC;F:AGH;E:HD;

     #

Oput:

     A B C F G D H E -> 3

 1 //id[]输入字母的编号
 2 //p[i]排列的字母编号 do{}先执行最小字典序的排列
 3
 4
 5 #include<cstdio>
 6 #include<cstring>
 7 #include<vector>
 8 #include<algorithm>
 9 using namespace std;
10
11 const int maxn=10,inf=0x7fffffff;
12 char letter[maxn], s[100];//字母,输入序列
13 int id[256]; //字母的编号
14 int p[maxn]; //全排列的遍历数组 ,存储的是每个字母的编号
15 int pos[maxn];//记录每个字母的位置,避免频繁使用strchr
16
17 int main(){
18     while(scanf(" %s",&s),s[0]!=‘#‘){
19         int len=strlen(s),n=0;
20         for(char ch=‘A‘;ch<=‘Z‘;ch++)if(strchr(s,ch)!=NULL){
21             letter[n]=ch;
22             id[ch]=n++;
23         }
24         vector<int> u,v;
25         for(int i=0;i<len;i++){
26             int t=i;//记录起始节点
27             i+=2;
28             while(i<len && s[i]!=‘;‘){
29                 u.push_back(id[s[t]]);//加入起始节点
30                 v.push_back(id[s[i]]);//加入起始节点的相邻节点
31                 i++;
32             }
33         }
34         //遍历+剪枝
35         int bandwidth=0,res=inf;
36         int bestP[maxn];//存储最终结果
37         for(int i=0;i<n;i++)p[i]=i;
38         do{
39             bandwidth=0;//初始化别忘了
40             for(int i=0;i<n;i++)pos[p[i]]=i;//记录编号为pi的节点的位置
41             for(int i=0;i<u.size();i++){
42                 bandwidth=max(bandwidth,abs(pos[u[i]]-pos[v[i]]));
43                 if(bandwidth>=res)break;//剪枝
44             }
45             if(bandwidth<res){
46                 memcpy(bestP,p,sizeof(p));//memcpy比较快
47                 res=bandwidth;
48             }
49         }while(next_permutation(p,p+n));
50         for(int i=0;i<n;i++)printf("%c ",letter[bestP[i]]);
51         printf("-> %d\n",res);
52     }
53 }
时间: 2024-10-09 23:54:52

Uva140 Bandwidth 全排列+生成测试法+剪枝的相关文章

递归解决全排列生成算法

排列:从n个元素中任取m个元素,并按照一定的顺序进行排列,称为排列: 全排列:当n==m时,称为全排列: 比如:集合{ 1,2,3}的全排列为: { 1 2 3} { 1 3 2 } { 2 1 3 } { 2 3 1 } { 3 2 1 } { 3 1 2 } 方法一: 我们可以将这个排列问题画成图形表示,即排列枚举树,比如下图为{1,2,3}的排列枚举树,此树和我们这里介绍的算法完全一致: 算法思路: (1)n个元素的全排列=(n-1个元素的全排列)+(另一个元素作为前缀): (2)出口:如

UVa140 Bandwidth 小剪枝+双射小技巧+枚举全排列+字符串的小处理

给出一个图,找出其中的最小带宽的排列.具体要求见传送门:UVa140 这题有些小技巧可以简化代码的编写. 本题的实现参考了刘汝佳老师的源码,的确给了我许多启发,感谢刘老师. 思路: 建立双射关系:从字符A到字符Z遍历输入的字符串,用strchr函数将输入中出现的字符找出,并将找出的字符进行编号,用letter和id分别存储字符和对应的编号 降维:输入中给出的,是类似于邻接表形式的二维形式,如果我们用二维数据结构,将增加处理时对于输出细节的处理难度,用 2个 vector将输出降低到1维,简化了计

UVA-140 Bandwidth (回溯+剪枝)

题目大意:求一个使带宽最小的排列和最小带宽.带宽是指一个字母到其相邻字母的距离最大值. 题目分析:在递归生成全排列的过程中剪枝,剪枝方案还是两个.一.当前解不如最优解优时,减去:二.预测的理想解不必最优解优时,减去.将与当前最后一个位置上的字母相邻的字母全部接过来,便得理想解. 代码如下: # include<iostream> # include<cstdio> # include<string> # include<vector> # include&l

uva140 Bandwidth

https://vjudge.net/problem/UVA-140 给出一个图,构造一个排列,使图上相邻节点在排列中的距离最大值最小 没有剪枝,竟然10ms过了,~~~ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; bool b[26][26],use[10]; char s[100],ans[10],tmp[26]; int len,v[26],num,minn

全排列生成算法

全排列的生成算法, next_permutation_1 可以用于生成多重集的全排列,next_permutation_2不能用于多重集 #include <cstdio> #include <cstring> #include <vector> using namespace std; bool next_permutation_1(vector<int>& vec){ int n = vec.size()-1; for(;n>0;n--){

UVa140 Bandwidth (枚举排列)

链接:http://acm.hust.edu.cn/vjudge/problem/19399分析:将结点字母用数字0~n-1表示,id[ch]将字符映射到对应的数字编号,letter将数字编号映射到对应的字符,用两个vector将每个结点的相邻结点编号存下来,然后枚举0~n-1位置上的结点编号,用pos记录每个结点编号所在的位置方便以后查找,然后就是遍历vector,第一个vector代表结点编号i,第二个vector代表结点i的相邻结点编号,找出最远距离,如果当前找到的最远距离已经大于或等于a

HDOJ-ACM1016(JAVA) 字典序全排列,并剪枝

转载声明:原文转自http://www.cnblogs.com/xiezie/p/5576273.html 题意: 一个环是用图中所示的n个圆组成的.把自然数1.2.…….n分别放入每个圆中,并在相邻的圆中的数值总和为一个质数. 注:第一圈数应该是1. 输出: 输出格式显示为下面的示例.每一行代表在环里圆中的数从1开始顺时针和逆时针.数字的数量必须满足上述要求.按字典顺序打印解决方案. 你是写一个程序,完成上述过程. 每一种情况下打印一条空白线. 题目分析: 首先,因为需要遍历多次,质数不可能每

机器学习笔记(九)——决策树的生成与剪枝

一.决策树的生成算法 基本的决策树生成算法主要有ID3和C4.5, 它们生成树的过程大致相似,ID3是采用的信息增益作为特征选择的度量,而C4.5采用信息增益比.构建过程如下: 从根节点开始,计算所有可能的特征的信息增益(信息增益比),选择计算结果最大的特征. 根据算出的特征建立子节点,执行第一步,直到所有特征的信息增益(信息增益比)很小或者没有特征可以选择为止. 以上算法只有树的生成,容易产生过拟合. 二.决策树的剪枝 决策树对于训练数据有很好的分类,但是对于未知测试集的分类并没有那么准确,这

【STL】全排列生成算法:next_permutation

C++/STL中定义的next_permutation和prev_permutation函数是非常灵活且高效的一种方法,它被广泛的应用于为指定序列生成不同的排列. next_permutation函数将按字母表顺序生成给定序列的下一个较大的排列,直到整个序列为降序为止. prev_permutation函数与之相反,是生成给定序列的上一个较小的排列. 所谓“下一个”和“上一个”,举一个简单的例子: 对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b