UVa12118
每两个城市之间都有道路连通,检查员要通过指定的道路,途中可以经过其它未指定的道路。通过每条道路的时间是一样的,求出通过所有指定道路要花费的最小时间。
如果指定的道路属于不同的连通子图,则检查员需要经由一条额外的道路来连接不同的连通子图,总共需要经由的额外道路是连通子图的数量减1。
下面再来考虑连通子图中需要添加额外道路的数量。假设从任意的城市出发,尽量不重复的通过了尽可能多的道路,如果此时还有未通过的指定道路,那么检查员可以经由一条未指定的道路直接到达该指定道路的起点,也可以重复通过指定道路到达该指定道路的起点,显然前者花费的时间是不大于后者的,所以最优解应该是只通过一次指定道路的,那么问题就变成了在无向连通子图中添加若干条边来构建一条欧拉通路。
无向连通图中存在欧拉通路的充分条件是奇度数的顶点个数为2。由于每条边贡献一个出度和一个入度,所以图中总度数一定为偶数,据此可以推出奇度数顶点数量为偶数,同时每添加一条边就能减少两个奇度数的顶点,所以需要添加边的条数为奇度数顶点个数减2。
#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:
Solution(const vector<vector<bool>>& graph, size_t E, size_t T) : graph(graph), visited(graph.size(), false), edges(E), time(T)
{
CountSubgraph();
for (const vector<size_t>& subgraph : subgraphs)
{
size_t n = CountVertexWithOddDegree(subgraph);
if (n > 2) edges += (n - 2) / 2;
}
edges += subgraphs.empty() ? 0 : subgraphs.size() - 1;
time *= edges;
}
size_t TotalTraverseTime()
{
return time;
}
private:
vector<vector<bool>> graph;
vector<bool> visited;
vector<vector<size_t>> subgraphs;
size_t edges, time;
void CountSubgraph()
{
for (size_t i = 0; i < graph.size(); i++)
{
if (!visited[i]) {
visited[i] = true;
subgraphs.push_back(vector<size_t>());
subgraphs.back().push_back(i);
dfs(i, subgraphs.back());
if (subgraphs.back().size() == 1) {
subgraphs.pop_back();
}
}
}
}
void dfs(size_t curr, vector<size_t> &subgraph)
{
for (size_t adj = 0; adj < graph[curr].size(); adj++)
{
if (graph[curr][adj] && !visited[adj]) {
visited[adj] = true;
subgraph.push_back(adj);
dfs(adj, subgraph);
}
}
}
size_t CountVertexWithOddDegree(const vector<size_t> &subgraph)
{
size_t num = 0;
for (size_t i : subgraph)
{
size_t degree = 0;
for (size_t j = 0; j < graph[i].size(); j++)
{
if (graph[i][j]) degree++;
}
if (degree % 2 == 1) num++;
}
return num;
}
};
int main()
{
int cases = 0;
size_t V, E, T;
while (cin >> V >> E >> T) {
if (V == 0 && E == 0 && T == 0) break;
vector<vector<bool>> graph(V, vector<bool>(V, false));
size_t i, j;
for (size_t e = 0; e < E; e++)
{
cin >> i >> j;
graph[i - 1][j - 1] = graph[j - 1][i - 1] = true;
}
Solution solution(graph, E, T);
cout << "Case " << ++cases << ": " << solution.TotalTraverseTime() << endl;
}
}
/*
5 3 1
1 2
1 3
4 5
4 4 1
1 2
1 4
2 3
3 4
0 0 0
*/
本文解析了UVa12118检查员困境问题,阐述了如何利用图论中的欧拉通路概念求解最短路径问题。文章详细介绍了算法实现过程,包括连通子图的划分、奇度数顶点计数及所需添加边数的计算。
1724

被折叠的 条评论
为什么被折叠?



