UVa 10968 KuPellaKes

题目描述

在古代,Koorosh\texttt{Koorosh}Koorosh 发明了时间机器并穿越到 Basm\texttt{Basm}Basm 国王的时代,不幸被抓住。为了活命,他需要解决一个问题:给定一个由 nnn 个城市和 mmm 条道路组成的领土 KuPellaKes\texttt{KuPellaKes}KuPellaKes,要求删除最少的道路,使得每个城市都有偶数个相邻城市,并且每个城市至少保留一个相邻城市。初始图中最多有两个城市的相邻城市数量为奇数。

输入格式

输入包含多个测试用例。每个测试用例第一行包含两个整数 nnnmmm,分别表示城市数量和道路数量。接下来 mmm 行,每行包含两个整数 iiijjj,表示城市 iii 和城市 jjj 之间有一条双向道路。输入以一行三个零结束。

输出格式

对于每个测试用例,输出需要删除的最少道路数量,如果无法完成任务,输出 Poor Koorosh

题目分析

这是一个图论问题,我们需要在满足特定度数条件的情况下删除最少的边。关键观察点如下:

  1. 度数要求:每个顶点的度数必须为偶数且至少为 111
  2. 初始条件:图中最多有两个奇数度顶点
  3. 操作方式:通过删除边来调整顶点度数

解题思路

根据图论中的握手引理,无向图中所有顶点度数之和为偶数,因此奇数度顶点的数量必须为偶数。题目已经保证最多有两个奇数度顶点,我们只需要考虑以下三种情况:

情况一:没有奇数度顶点

如果图中所有顶点的度数都是偶数:

  • 检查是否所有顶点都有至少一个邻居(度数 ≥1\geq 11
  • 如果满足条件,不需要删除任何边,输出 000
  • 如果有孤立顶点(度数为 000),输出 Poor Koorosh
情况二:恰好有两个奇数度顶点

设这两个奇数度顶点为 uuuvvv,我们需要找到从 uuuvvv 的一条路径,通过删除这条路径上的边来调整度数:

  • 度数变化规律

    • 删除路径上的一条边会使两个端点的度数各减少 111
    • 对于路径上的中间顶点,会减少 222 条边(进入边和离开边)
  • 约束条件

    • 起点 uuu 和终点 vvv:原始度数必须 >1> 1>1(删除 111 条边后度数 ≥1\geq 11
    • 中间顶点:原始度数必须 >2> 2>2(删除 222 条边后度数 ≥1\geq 11
  • 解决方案

    • 使用 BFS\texttt{BFS}BFS 寻找从 uuuvvv 的最短路径
    • BFS\texttt{BFS}BFS 过程中,只允许访问度数 >2> 2>2 的顶点作为中间顶点
    • 路径长度即为需要删除的边数
情况三:其他情况

如果奇数度顶点数量不是 000222,根据题目约束这不会发生,但为了完整性,输出 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 寻找满足约束的最短路径,我们能够高效地解决这个问题。算法充分利用了题目给出的特殊条件(最多两个奇数度顶点),使得解决方案既简洁又高效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值