题目描述
在古代,Koorosh\texttt{Koorosh}Koorosh 发明了时间机器并穿越到 Basm\texttt{Basm}Basm 国王的时代,不幸被抓住。为了活命,他需要解决一个问题:给定一个由 nnn 个城市和 mmm 条道路组成的领土 KuPellaKes\texttt{KuPellaKes}KuPellaKes,要求删除最少的道路,使得每个城市都有偶数个相邻城市,并且每个城市至少保留一个相邻城市。初始图中最多有两个城市的相邻城市数量为奇数。
输入格式
输入包含多个测试用例。每个测试用例第一行包含两个整数 nnn 和 mmm,分别表示城市数量和道路数量。接下来 mmm 行,每行包含两个整数 iii 和 jjj,表示城市 iii 和城市 jjj 之间有一条双向道路。输入以一行三个零结束。
输出格式
对于每个测试用例,输出需要删除的最少道路数量,如果无法完成任务,输出 Poor Koorosh。
题目分析
这是一个图论问题,我们需要在满足特定度数条件的情况下删除最少的边。关键观察点如下:
- 度数要求:每个顶点的度数必须为偶数且至少为 111
- 初始条件:图中最多有两个奇数度顶点
- 操作方式:通过删除边来调整顶点度数
解题思路
根据图论中的握手引理,无向图中所有顶点度数之和为偶数,因此奇数度顶点的数量必须为偶数。题目已经保证最多有两个奇数度顶点,我们只需要考虑以下三种情况:
情况一:没有奇数度顶点
如果图中所有顶点的度数都是偶数:
- 检查是否所有顶点都有至少一个邻居(度数 ≥1\geq 1≥1)
- 如果满足条件,不需要删除任何边,输出 000
- 如果有孤立顶点(度数为 000),输出
Poor Koorosh
情况二:恰好有两个奇数度顶点
设这两个奇数度顶点为 uuu 和 vvv,我们需要找到从 uuu 到 vvv 的一条路径,通过删除这条路径上的边来调整度数:
-
度数变化规律:
- 删除路径上的一条边会使两个端点的度数各减少 111
- 对于路径上的中间顶点,会减少 222 条边(进入边和离开边)
-
约束条件:
- 起点 uuu 和终点 vvv:原始度数必须 >1> 1>1(删除 111 条边后度数 ≥1\geq 1≥1)
- 中间顶点:原始度数必须 >2> 2>2(删除 222 条边后度数 ≥1\geq 1≥1)
-
解决方案:
- 使用 BFS\texttt{BFS}BFS 寻找从 uuu 到 vvv 的最短路径
- 在 BFS\texttt{BFS}BFS 过程中,只允许访问度数 >2> 2>2 的顶点作为中间顶点
- 路径长度即为需要删除的边数
情况三:其他情况
如果奇数度顶点数量不是 000 或 222,根据题目约束这不会发生,但为了完整性,输出 Poor Koorosh。
算法复杂度
- 时间复杂度:O(n+m)O(n + m)O(n+m),每个测试用例使用 BFS\texttt{BFS}BFS 遍历图
- 空间复杂度:O(n+m)O(n + m)O(n+m),用于存储图和距离信息
代码实现
// KuPellaKes
// UVa ID: 10968
// Verdict: Accepted
// Submission Date: 2025-11-17
// UVa Run Time: 0.020s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
while (cin >> n >> m && (n || m)) {
vector<vector<int>> graph(n + 1);
vector<int> degree(n + 1, 0);
// 构建图和计算度数
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
degree[u]++;
degree[v]++;
}
// 统计奇数度顶点
vector<int> oddVertices;
for (int i = 1; i <= n; i++)
if (degree[i] % 2 != 0)
oddVertices.push_back(i);
// 情况一:没有奇数度顶点
if (oddVertices.size() == 0) {
bool allHaveNeighbors = true;
for (int i = 1; i <= n; i++)
if (degree[i] == 0) {
allHaveNeighbors = false;
break;
}
cout << (allHaveNeighbors ? "0" : "Poor Koorosh") << endl;
}
// 情况二:恰好有两个奇数度顶点
else if (oddVertices.size() == 2) {
int u = oddVertices[0], v = oddVertices[1];
// 检查起点和终点是否满足度数条件
if (degree[u] <= 1 || degree[v] <= 1) {
cout << "Poor Koorosh" << endl;
continue;
}
// BFS寻找最短路径
vector<int> dist(n + 1, -1);
queue<int> q;
dist[u] = 0;
q.push(u);
while (!q.empty()) {
int current = q.front();
q.pop();
for (int neighbor : graph[current])
if (dist[neighbor] == -1)
// 中间顶点必须度数>2,终点v直接允许
if (neighbor == v || degree[neighbor] > 2) {
dist[neighbor] = dist[current] + 1;
q.push(neighbor);
}
}
cout << (dist[v] != -1 ? to_string(dist[v]) : "Poor Koorosh") << endl;
}
// 情况三:其他情况
else
cout << "Poor Koorosh" << endl;
}
return 0;
}
总结
本题的关键在于理解度数变化的规律和路径删除对度数的影响。通过 BFS\texttt{BFS}BFS 寻找满足约束的最短路径,我们能够高效地解决这个问题。算法充分利用了题目给出的特殊条件(最多两个奇数度顶点),使得解决方案既简洁又高效。
1253

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



