例题7-6 UVA140 Bandwidth(43行AC代码)

紫书刷题进行中,题解系列【GitHub|CSDN

例题7-6 UVA140 Bandwidth(43行AC代码)

题目大意

给定一个无向图,将节点排序后,定义顶点i的带宽b(i)为顶点i与相邻结点在排列中的最大距离,而一个排序的带宽为b(i)的最大值。现要求出带宽最小的排列,存在多解则输出字典序最小者

思路分析

本质是N个顶点的全排列问题,为了解决字典序问题,将顶点先升序排列。计算过程中,仅遇到带宽比当前最小的还小才更新(等于也不更新,利用定序规律)。

那么能否进行剪枝优化呢?

本题不像八皇后问题,有直接的约束条件,在枚举过程就可以避免扩展哪些不可能的点。但是对本题进行仔细分析,可发现,如果当前序列存在两个结点距离大于目前最小带宽,说明该序列一定不是最优,可剪枝。

再进一步,假设搜索到结点u时,还有m个相邻顶点未确定,说明它未来的带宽至少为m,若m>=目前最优k,说明该排序一定不是最优,可剪枝

注意点

  • stringstream很耗时,若时间要求高,需自己写分割函数

AC代码(C++11,全排列+优化分析)

#include<bits/stdc++.h>
using namespace std;
int minWidth, vis[26]; // 最小带宽;标记访问数组
map<char,set<char> > graph; // 邻接表存图
vector<char> ans, tans, node; // 存储最终答案;dfs中间存储;升序排列的顶点集
void calBandwidth() { // 计算带宽
    map<char,int> pos;
    for (int i=0; i < tans.size(); i ++) pos[tans[i]] = i; // 记录每个点的位置
    int maxW = -1;
    for (char u : tans) { // 枚举每个点
        for (char v : graph[u]) maxW = max(maxW, abs(pos[u]-pos[v])); // 计算最大距离
    }
    if (minWidth > maxW) {
        minWidth = maxW; // 严格大于
        ans = tans; // 存储结果
    }
}
void dfs(int cnt) { // dfs(i)表示已确定了i个元素
    if (cnt == node.size()) calBandwidth(); // 一个完整排列
    else {
        for (char v : node) {
            if (vis[v-'A'] == 0) {
                tans.push_back(v); vis[v-'A']=1;
                dfs(cnt+1);
                tans.pop_back(); vis[v-'A']=0; // 结束记得清除标记
            }
        }
    }
}
int main() {
    string line, s;
    while (getline(cin, line) && line[0] != '#') {
        graph.clear(); stringstream input(line);
        while (getline(input,s,';')) {
            for (char v : s.substr(2)) {graph[s[0]].insert(v); graph[v].insert(s[0]);} // 无向图构建
        }
        node.clear(); for (auto p : graph) node.push_back(p.first); // 结点集合
        minWidth = 0x3ffffff; memset(vis, 0, sizeof(vis)); dfs(0); // 初始化后dfs
        for (int i=0; i < ans.size(); i ++) printf("%c ", ans[i]); // 输出
        printf("-> %d\n", minWidth); 
    }
    return 0;
}
发布了128 篇原创文章 · 获赞 87 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_40738840/article/details/104460775