本题题意:寻找一个排列,在此排序中,带宽的长度最小(带宽是指:任意一点v与其距离最远的且与v有边相连的顶点与v的距离的最大值),若有多个,按照字典序输出最小的哪一个。

解题思路:

  方法一:由于题目说结点的个数最多是8个,所以,最先想到的方法是暴力枚举,将所有的结点全排列,然后找到宽带长度最小的那一个,此方法不会超时。

  方法二:利用回溯法,将所有肯能的情况都遍历一遍,保存目前最短的宽带的长度minn,若当前的宽带长度大于minn,就进行剪枝,此题要注意,此题的结点不一定是从A开始的,所以要建立字母的映射,保存结点,同是注意输入时空格的处理。

暴力枚举的代码:

 #include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
char str[];
int a[][],b[],c[][],visit[];
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(gets(str)){
memset(visit,,sizeof(visit));
memset(a,,sizeof(a));
memset(b,,sizeof(b));
memset(c,,sizeof(c));
if(str[]=='#') break;
else{
for(int i=;i<strlen(str);){
if(str[i]==' '){
i++;
continue;
}
int t=str[i++]-'A'+;
while(str[i]==' '){i++;}
i++;
while(i<strlen(str)){
if(str[i]==' '){
i++;
continue;
}
if(str[i]==';'){
i++;
break;
}
int k=str[i++]-'A'+;
a[t][k]=;
a[k][t]=;
}
}
}
int num=;
for(int i=;i<;i++){
int sum=;
for(int j=;j<;j++){
sum=sum+a[i][j];
}
if(sum){b[num++]=i;}
}
int minn=;
do{
int maxx=;
for(int i=;i<num;i++){
for(int j=;j<=;j++){
if(a[b[i]][j]){
for(int k=i+;k<;k++){
if(b[k]==j) maxx=max(maxx,k-i);
}
}
}
}
if(!visit[maxx]){
for(int i=;i<num;i++){
c[maxx][i]=b[i];
}
visit[maxx]=;
}
minn=min(minn,maxx);
}while(next_permutation(b,b+num));    //全排列函数。耗时,但是节省代码的长度时可用
for(int i=;i<num;i++){
printf("%c ",c[minn][i]+'A'-);
}
printf("-> %d\n",minn);
}
return ;
}

递归回溯的代码:

 #include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
char str[];
int minn,maxx,num;
int a[][],b[],c[],visit[],goal[]; void dfs(int n,int maxx){
if(n==num){
minn=maxx;
memcpy(goal,c,sizeof(c));
return;
}
for(int i=;i<num;i++){
if(!visit[b[i]]){
visit[b[i]]=;
c[n]=b[i];
int w=;
for(int j=;j<n;j++){
if(a[b[i]][c[j]]){
w=n-j;
break;
}
}
int max_w=max(maxx,w);
if(max_w<minn){
dfs(n+,max_w);
}
visit[b[i]]=;
}
}
} int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(gets(str)){
memset(visit,,sizeof(visit));
memset(a,,sizeof(a));
memset(b,,sizeof(b));
memset(c,,sizeof(c));
if(str[]=='#') break;
else{
for(int i=;i<strlen(str);){
if(str[i]==' '){
i++;
continue;
}
int t=str[i++]-'A'+;
while(str[i]==' '){i++;}
i++;
while(i<strlen(str)){
if(str[i]==' '){
i++;
continue;
}
if(str[i]==';'){
i++;
break;
}
int k=str[i++]-'A'+;
a[t][k]=;
a[k][t]=;
}
}
}
num=;
for(int i=;i<;i++){
int sum=;
for(int j=;j<;j++){
sum=sum+a[i][j];
}
if(sum){b[num++]=i;}
}
minn=;
maxx=;
dfs(,);
for(int i=;i<num;i++)
printf("%c ",goal[i]+'A'-);
printf("-> %d\n",minn); }
return ;
}

提供几组测试数据:

A:FB;B:GC;D:GC;F:AGH;E:HD
A:FB;B:GC;D:GC;F:AGH;E:H
A:B;B:C;C:D;D:E;E:F;F:G;G:H
A:B;B:C;C:D;D:E;E:F;F:G;G:H;H:A
A:B;B:CE;C:D;D:E;E:F;F:G;G:H;H:A
A:B;B:CE;C:DG;D:E;E:F;F:G;G:H;H:A
A:BCDEFGH;B:ACDEFGH;C:ABDEFGH;D:ABCEFGH;E:ABCDFGH;F:ABCDEGH;G:ABCDEFH;H:ABCDEFG
#

答案:

A B C F G D H E -> 3
C D B G A F E H -> 2
A B C D E F G H -> 1
A B H C G D F E -> 2
C D B E A F H G -> 2
A B H C E G D F -> 3
A B C D E F G H -> 7

递归回溯 UVa140 Bandwidth宽带的更多相关文章

  1. LeetCode || 递归 / 回溯

    呜呜呜 递归好不想写qwq 求“所有情况”这种就递归 17. Letter Combinations of a Phone Number 题意:在九宫格上按数字,输出所有可能的字母组合 Input: ...

  2. FZU - 2038 -E - Another Postman Problem (思维+递归+回溯)

    Chinese Postman Problem is a very famous hard problem in graph theory. The problem is to find a shor ...

  3. 40. 组合总和 II + 递归 + 回溯 + 记录路径

    40. 组合总和 II LeetCode_40 题目描述 题解分析 此题和 39. 组合总和 + 递归 + 回溯 + 存储路径很像,只不过题目修改了一下. 题解的关键是首先将候选数组进行排序,然后记录 ...

  4. UVA-140 Bandwidth (回溯+剪枝)

    题目大意:求一个使带宽最小的排列和最小带宽.带宽是指一个字母到其相邻字母的距离最大值. 题目分析:在递归生成全排列的过程中剪枝,剪枝方案还是两个.一.当前解不如最优解优时,减去:二.预测的理想解不必最 ...

  5. uva140 - Bandwidth

    Bandwidth Given a graph (V,E) where V is a set of nodes and E is a set of arcs in VxV, and an orderi ...

  6. 假回溯-uva140带宽

    题目链接:https://vjudge.net/problem/UVA-140 题解:这道题利用全排函数即可解决,但是这道题技巧性强,稍微不注意就会超时,一开始没有想起全排函数,自己写回溯全排超时了, ...

  7. C语言递归回溯法迷宫求解

    本例将随机产生一个10*10的迷宫输出后,在下面输出此迷宫的解法. 解法为从坐标(1,1)处进入,从(8,8,)出去,优先线路为先右后下再上最后为左. 不少人求解此题时运用的栈的相关知识,本例寻找线路 ...

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

    给出一个图,找出其中的最小带宽的排列.具体要求见传送门:UVa140 这题有些小技巧可以简化代码的编写. 本题的实现参考了刘汝佳老师的源码,的确给了我许多启发,感谢刘老师. 思路: 建立双射关系:从字 ...

  9. [LeetCode] Sudoku Solver 解数独,递归,回溯

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...

随机推荐

  1. CLR Via C#: 类型基础

    所有类型都从System.Object派生 一下两个类型定义是完全一致的 class Employee { } class Employee : System.Object { } 由于所有类型最终都 ...

  2. 跨域请求CORS

    参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS http://www.ruanyifeng.com/b ...

  3. ASP.NET MVC中URL末尾斜杠的实现

    在网站的SEO优化中,通常都会涉及到URL结尾斜杠的问题. http://blog.sina.com.cn/s/blog_828e7ce40100srj1.html http://www.dengyo ...

  4. JavaScript系列----正则表达式

    1.正则表达式 1.1.正则表达式的类型 正则表达式在JavaScript中,提供了一种内置的构造函数--RegExp. 正则表达式有三种匹配模式: g: 表示全局模式,即模式应用于所有的字符串,而非 ...

  5. Linux 基本命令-----常用操作分类

    Linux/Unix 命令格式: 命令名 [选项] [参数] 注:[]中的内容代表内容可以省略 例:$ ls $ ls -l #-l 是选项 开始符号: 文件名 或 文件夹名 .当前文件夹 ..上一级 ...

  6. 学习RocketMQ (一) 安装并且启动MQ

    1.使用RocketMQ 的 软件要求 64bit OS, Linux/Unix/Mac is recommended;64bit JDK 1.8+;Maven 3.2.xGit 1)安装Linux ...

  7. JavaScript 数组基本操作

    简介 数组操作无论是在JavaScript中还是在其他语言中都是很常见.经常会用到的,现在我把JavaScript 数组基本操作整理一下,供大家参考学习.里边包含我自己的见解以及案例,希望能够帮助大家 ...

  8. StackExchange.Redis学习笔记(三)

    这一章主要写一些StackExchange.Redis的配置及不太经常用到的函数 数据库连接 下面是我的连接字符串,里面指定了地址,密码,及默认的数据库 Redis启动后默认会分成0-15个数据库,不 ...

  9. javascript面向对象编程(OOP)——汇总

    目录 一.JS的解析与执行过程 预处理阶段 执行阶段 二.作用域 块作用域 函数作用域 动态作用域 词法作用域 三.闭包 什么是闭包 闭包的好处 四.类与对象 对象 类 原型(prototype) t ...

  10. SparseArray,SparseBooleanArray和SparseIntArray

    package android.util; import com.android.internal.util.ArrayUtils; /** * SparseArrays 利用integer去管理ob ...