Time limit: 3.000 seconds
限时3.000秒

Problem
问题

Given a graph (V,E) where V is a set of nodes and E is a set of arcs in VxV, and an ordering on the elements in V, then the bandwidth of a node v is defined as the maximum distance in the ordering between v and any node to which it is connected in the graph. The bandwidth of the ordering is then defined as the maximum of the individual bandwidths. For example, consider the following graph:
给定一个图(V,E),其中V为顶点的集合,E为边的集合,属于VxV。给定V中元素的一种排序,那么顶点v的带宽定义如下:在当前给定的排序中,与v距离最远的且与v有边相连的顶点与v的距离。给定排序的带宽定义为各顶点带宽的最大值。例如考虑如下图:

This can be ordered in many ways, two of which are illustrated below:
此图可以给出多种排序,其中两个排序图示如下:


For these orderings, the bandwidths of the nodes (in order) are 6, 6, 1, 4, 1, 1, 6, 6 giving an ordering bandwidth of 6, and 5, 3, 1, 4, 3, 5, 1, 4 giving an ordering bandwidth of 5.
对于给出的这两个排序,它们各结点的带宽分别是(按排序顺序):6, 6, 1, 4, 1, 1, 6, 6,排序带宽为6,以及5, 3, 1, 4, 3, 5, 1, 4,排序带宽为5。

Write a program that will find the ordering of a graph that minimises the bandwidth.
写一个程序,找出该图的一种排序使其带宽最小。

Input
输入

Input will consist of a series of graphs. Each graph will appear on a line by itself. The entire file will be terminated by a line consisting of a single#. For each graph, the input will consist of a series of records separated by `;'. Each record will consist of a node name (a single upper case character in the the range `A' to `Z'),followed by a `:' and at least one of its neighbours. The graph will contain no more than 8 nodes.
输入由一系列的图构成。每个图独占一行。一个仅包含“#”字符的一行输入标志整个输入文件结束。对于每个图的输入,都包含一系列由“;”隔开的记录。每个记录包含一个结点名(一个大写字母,范围是“A”到“Z”),接着是一个“:”,然后是一些该结点的邻居结点。图中不会包含超过8个结点。

Output
输出

Output will consist of one line for each graph, listing the ordering of the nodes followed by an arrow (->) and the bandwidth for that ordering. All items must be separated from their neighbours by exactly one space. If more than one ordering produces the same bandwidth, then choose the smallest in lexicographic ordering, that is the one that would appear first in an alphabetic listing.
每个图对应一行输出,列出排序的结点,然后是一个箭头(->)以及该排序的带宽值。所有项都应由一个空格与它相邻的项隔开。如果同一个带宽有多种排序方法,取字母序最小的一种排序,也就是取字母表排在前面的一种排序。

Sample input
示例输入

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

Analysis
分析

典型的优化问题,一个可行解就是一个排序,目标函数就是解的带宽。但ACM的优化问题一定是使用确定性算法的(与包含随机元素的现代优化算法如遗传、粒子相对),确定性优化算法就那么几种,贪心、动态规划、单纯行(解线性规划)还有就是暴力。注意到题中专门强调:图不会超过8个结点,结点的名字都是从“A”到“Z”,相同带宽的排序取字典序靠前等,所有的线索都指向了一种算法:暴力搜索。

从要求的“字典序”得到启发:全排列生成算法。剩下的问题就是以何种数据结构来存储,以便快速的查找顶点和计算带宽。对于一种顶点的排序,要查找指定顶点所在的位置,最快的方法就是使用标记数组。由于题中限定的顶点的取值范转:“A”到“Z”,因此用一个26个元素的数组即可记录每个顶点在排序中的位置。

记下顶点的位置后,需要用最快的方式查出每个顶点到它的邻居的距离,这实际就是在当前排序中找出相距最远的一条边。因此只要遍历图中所有的边,计算其在当前排序中的距离,并记录最远的距离即可。图可以用边的集合来表示图,每个边用两个顶点来表示。由于是无向图,因此可使边的两个顶点程左小右大排序,然后保证无重边即可。

Solution
解答

#include "stdafx.h"
#include <algorithm>
#include <iostream>
#include <vector>
#include <string> typedef std::pair<char, char> NODEPAIR;
typedef std::vector<char>::iterator NODE_ITER;
typedef std::string::iterator STR_ITER;
typedef std::vector<NODEPAIR>::iterator GRAPH_ITER; int main(void)
{
char idxTbl[32]; // 从顶点编号到其在某种排序中的位置的对应表
std::string strLine; // 存储一行输入的字符串
for (; std::getline(std::cin, strLine) && strLine[0] != '#'; ) {
std::vector<NODEPAIR> graph; // 数组中每个元素为一条边,用一对顶点的编号表示
std::vector<char> nodes; // 记录一种顶点的排序
// 为方便判断一行输入的结束,在行层添加分号
strLine.push_back(';');
// 循环处理当前输入行的每一个字符
for (STR_ITER i = strLine.begin(); i != strLine.end(); ++i) {
// 用所有边的顶点对来表示图,nFrom是冒号前的顶点,nTo是冒号后的顶点
char nFrom = *i - 'A'; // 每个顶点的编号为其字母的ASCII码-'A'
// 有些顶点只出现在冒号前,有些只出现在冒号后,因此nFrom和nTo都需添加
nodes.push_back(nFrom);
// 遍历冒号后面直到分号的顶点,这些顶点用nTo表示
for (i += 2; *i != ';'; ++i) {
char nTo = *i - 'A'; // 每个顶点的编号为其字母的ASCII码-'A'
nodes.push_back(nTo);
// 保证添加到图中的顶点对(边)中编号较小的顶点在前,避免无向图的重复边
if (nFrom > nTo)
graph.push_back(NODEPAIR(nFrom, nTo));
else if (nFrom < nTo)
graph.push_back(NODEPAIR(nTo, nFrom));
}
}
// 对图的所有顶点对(边)排序去重
std::sort(graph.begin(), graph.end());
graph.erase(std::unique(graph.begin(), graph.end()), graph.end());
// 对顶点数组排序去重,作为第一种排序(升序最小)
std::sort(nodes.begin(), nodes.end());
nodes.erase(std::unique(nodes.begin(), nodes.end()), nodes.end());
std::vector<char> minOrder; // 记录具有最小带宽的排序
char nMinBw = char(nodes.size()); // 记录具有最小的带宽,初始化为数组长度
for (bool bNext = true; bNext; ) { // 遍历所有排序
char nCnt = 0, nOrderBw = 0;
// 扫描一遍当前的排序,求出每一个顶点在当前排序中的位置
for (NODE_ITER i = nodes.begin(); i != nodes.end(); ++i) {
idxTbl[*i] = nCnt++;
}
// 遍历图中的所有顶点对,找出在当前排序中距离最远的顶点对作为当前排序的带宽
for (GRAPH_ITER i = graph.begin(); i != graph.end(); ++i) {
char nCur = char(std::abs(idxTbl[i->first] - idxTbl[i->second]));
if (nCur > nOrderBw)
nOrderBw = nCur;
}
// 如果当前排序的带宽小于已知最小带宽,则更新最小带宽和最小排序
if (nOrderBw < nMinBw) {
nMinBw = nOrderBw;
minOrder = nodes;
}
// 接字母序给出下一种排序
bNext = std::next_permutation(nodes.begin(), nodes.end());
}
// 按格式循环输出最小排序和它的带宽值
for (NODE_ITER i = minOrder.begin(); i != minOrder.end(); ++i) {
std::cout << char(*i + 'A') << ' ';
}
std::cout << "-> " << (int)nMinBw << std::endl;
}
return 0;
}

UVa OJ 140 - Bandwidth (带宽)的更多相关文章

  1. UVA - 140 Bandwidth(带宽)(全排列)

    题意:给定图,求是带宽最小的结点排列. 分析:结点数最多为8,全排列即可.顶点范围是A~Z. #pragma comment(linker, "/STACK:102400000, 10240 ...

  2. uva 140 bandwidth (好题) ——yhx

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

  3. UVa 140 Bandwidth【枚举排列】

    题意:给出n个节点的图,和一个节点的排列,定义节点i的带宽b[i]为i和其相邻节点在排列中的最远的距离,所有的b[i]的最大值为这个图的带宽,给一个图,求出带宽最小的节点排列 看的紫书,紫书上说得很详 ...

  4. UVA 140 Bandwidth

    题意: 给出一个n个节点的图G,和一个节点的排列,定义节点i的带宽为i和相邻节点在排列中的最远距离,而所有带宽的最大值就是图的带宽,求让图的带宽最小的排列. 分析: 列出所有可能的排列,记录当前找到的 ...

  5. UVA 140 Bandwidth (dfs 剪枝 映射)

    题意: 给定一个n个结点的图G和一个结点的排列, 定义结点i的带宽b(i)为i和相邻结点在排列中的最远距离, 所有b(i)的最大值就是这个图的带宽, 给定G, 求让带宽最小的结点排列. 给定的图 n ...

  6. UVA - 820 Internet Bandwidth (因特网带宽)(最大流)

    题意:给出所有计算机之间的路径和路径容量后,求出两个给定结点之间的流通总容量.(假设路径是双向的,且两方向流动的容量相同) 分析:裸最大流.标号从1开始,初始化的时候注意. #pragma comme ...

  7. UVA 140 Brandwidth 带宽 (dfs回溯)

    看到next_permutation好像也能过╮(╯▽╰)╭ 这题学习点: 1.建图做映射 2.通过定序枚举保证字典序最小 3.strtok,sscanf,strchr等函数又复习了一遍,尽管程序中没 ...

  8. UVA 820 Internet Bandwidth 因特网宽带(无向图,最大流,常规)

    题意:给一个无向图,每条边上都有容量的限制,要求求出给定起点和终点的最大流. 思路:每条无向边就得拆成2条,每条还得有反向边,所以共4条.源点汇点已经给出,所以不用建了.直接在图上跑最大流就可以了. ...

  9. UVA 820 Internet Bandwidth

    题意: 给出双向图,求给出两点的流通总流量. 分析: 网络流中的增广路算法. 代码: #include <iostream>#include <cstring>#include ...

随机推荐

  1. log_bin_trust_function_creators变量解释

    在MySQL主从复制机器的master的数据库中创建function,报出如下错误: Error Code: 1418. This function has none of DETERMINISTIC ...

  2. OAF 使用 javascript 使某个按钮在5秒内不能重复点击

    首先要保证按钮是BUTTON,并且按钮事件设置firePartialAction. public class CuxXXXXPGCO extends OAControllerImpl { public ...

  3. Gruntjs: task之文件映射

    由于大多数的任务执行文件操作,Grunt提供了一个强大的抽象声明说明任务应该操作哪些文件.这里总结了几种src-dest(源文件-目标文件)文件映射的方式,提供了不同程度的描述和控制操作方式. 1. ...

  4. error C3872: "0xa0": 此字符不允许在标识符中使用

    整理:这是因为直接复制代码的问题.0xa0是十六进制数,换成十进制就是160,表示汉字的开始. 解决办法:在报错的代码行检查两边的空格,用英文输入法的空格替换掉. 万恶的网络,万恶的word,这些无厘 ...

  5. 安装.NET CORE

    需要安装两个包 https://github.com/dotnet/cli 1. .NET Core Installer 2. .NET Core SDK Installer

  6. 我的权限系统设计实现MVC4 + WebAPI + EasyUI + Knockout(四)授权代码维护

    一.前言 权限系统设计中,授权代码是用来控制数据访问权限的.授权代码说白了只是一树型结构的数据,没有什么其它的业务意义.那么这个页面的功能也就非常简单授权代码维护:新增.修改.删除授权代码数据. 二. ...

  7. C#基础之Attribute

    1.什么是Attribute 特性简单点理解就是为目标元素添加一些附加信息,这些附加信息我们可以在运行期间以反射的方式拿到.目标元素指的是程序集.模块.类.参数.属性等元素,附加信息指的是特性类中的成 ...

  8. Python3常用内置函数

    数学相关 abs(a) : 求取绝对值.abs(-1) max(list) : 求取list最大值.max([1,2,3]) min(list) : 求取list最小值.min([1,2,3]) su ...

  9. #Linux学习笔记# Linux系统查看文件内容的命令

    1.cat 连结多个文件的内容并显示在屏幕上:如果没有指定文件或文件名为“-”,则读取标准输入.语法如下: cat [option] ... [file] ... 常用的选项有: 选项-n:编号所有行 ...

  10. sql脚本比较大,sqlserver 无法导入,就用cmd命令执行

    osql简单用法:用来将本地脚本执行,适合sql脚本比较大点的情况,执行起来比较方便 1 osql -S serverIP -U sa -P 123 -i C:\script.sql serverIP ...