UVa OJ 140 - Bandwidth (带宽)
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 (带宽)的更多相关文章
- UVA - 140 Bandwidth(带宽)(全排列)
题意:给定图,求是带宽最小的结点排列. 分析:结点数最多为8,全排列即可.顶点范围是A~Z. #pragma comment(linker, "/STACK:102400000, 10240 ...
- 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 ...
- UVa 140 Bandwidth【枚举排列】
题意:给出n个节点的图,和一个节点的排列,定义节点i的带宽b[i]为i和其相邻节点在排列中的最远的距离,所有的b[i]的最大值为这个图的带宽,给一个图,求出带宽最小的节点排列 看的紫书,紫书上说得很详 ...
- UVA 140 Bandwidth
题意: 给出一个n个节点的图G,和一个节点的排列,定义节点i的带宽为i和相邻节点在排列中的最远距离,而所有带宽的最大值就是图的带宽,求让图的带宽最小的排列. 分析: 列出所有可能的排列,记录当前找到的 ...
- UVA 140 Bandwidth (dfs 剪枝 映射)
题意: 给定一个n个结点的图G和一个结点的排列, 定义结点i的带宽b(i)为i和相邻结点在排列中的最远距离, 所有b(i)的最大值就是这个图的带宽, 给定G, 求让带宽最小的结点排列. 给定的图 n ...
- UVA - 820 Internet Bandwidth (因特网带宽)(最大流)
题意:给出所有计算机之间的路径和路径容量后,求出两个给定结点之间的流通总容量.(假设路径是双向的,且两方向流动的容量相同) 分析:裸最大流.标号从1开始,初始化的时候注意. #pragma comme ...
- UVA 140 Brandwidth 带宽 (dfs回溯)
看到next_permutation好像也能过╮(╯▽╰)╭ 这题学习点: 1.建图做映射 2.通过定序枚举保证字典序最小 3.strtok,sscanf,strchr等函数又复习了一遍,尽管程序中没 ...
- UVA 820 Internet Bandwidth 因特网宽带(无向图,最大流,常规)
题意:给一个无向图,每条边上都有容量的限制,要求求出给定起点和终点的最大流. 思路:每条无向边就得拆成2条,每条还得有反向边,所以共4条.源点汇点已经给出,所以不用建了.直接在图上跑最大流就可以了. ...
- UVA 820 Internet Bandwidth
题意: 给出双向图,求给出两点的流通总流量. 分析: 网络流中的增广路算法. 代码: #include <iostream>#include <cstring>#include ...
随机推荐
- connect函数详解
不得不说,客户端的connect函数和服务端的accept函数是一对好基友,如果客户端没有去connect, 那么服务端的accept会一直在那里傻傻地痴痴地等待,我们先来看看connect函数的原型 ...
- Android自动化压力测试图解教程——Monkey工具
[置顶] Android自动化压力测试图解教程--Monkey工具 标签: 测试androidprofiling工具测试工具文档 2012-04-01 10:16 38185人阅读 评论(10) 收藏 ...
- 北京联想招聘-Android Framework高级工程师(7-10年) 加入qq 群:220486180 或者直接在此 留言咨询
Job ID #: 45038 Position Title: Android Framework高级工程师 Location: CHN-Beijing Functional Area: Resear ...
- [vim]vim 在win下乱码解决
vim在win下遇到汉字乱码早就知晓,本以为通过如下设置即可解决乱码问题 set encoding=utf-8 set fileencoding=utf-8,chinese 这样设置是可以解决源码文件 ...
- js浮点数精确计算(加、减、乘、除)
<SPAN style="FONT-SIZE: 18px">//说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精确的加 ...
- <实训|第三天>Linux登录界面的修改以及Richard Stallman、自由软件运动
在写博客之前我想说两点: 承认一个错误,昨天写的实训第二天,我把redhat6.7写成了Linux6.7,感谢热心人士的指出! 昨天写的文章名字太长了,今天改善,内容感觉表述不全,希望各位谅解! 官方 ...
- JS开发HTML5游戏《神奇的六边形》(三)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- cryptdb中wrapper.lua的分析
因为cryptDB是在mysql-proxy的基础上来实现了,可以看成是为mysql-proxy添加了新的.为mysql-proxy已经为开发人员提供了相应的接口.如果开发人员只需要通过lua脚本语言 ...
- WCF 入门(19)
前言 天气转凉,提前过冬了.感冒依旧没好,因为双休日伙食太好了,各种鱼各种肉. 第19集 创建然后抛出强类型的SOAP faults Creating and throwing strongly t ...
- searchBar控件
那就先了解一下UISearchBar控件吧! UISearchBar控件就是要为你完成搜索功能的一个专用控件.它集成了很多你意想不到的功能和特点! 首先,还是来普及一下UISearchBar控件API ...