PAT 1013. Battle Over Cities

It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.

For example, if we have 3 cities and 2 highways connecting city1-city2 and city1-city3. Then if city1 is occupied by the enemy, we must have 1 highway repaired, that is the highway city2-city3.

Input

Each input file contains one test case. Each case starts with a line containing 3 numbers N (<1000), M and K, which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then M lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to N. Finally there is a line containing K numbers, which represent the cities we concern.

Output

For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.
Sample Input
3 2 3
1 2
1 3
1 2 3

Sample Output
1
0
0

这道题目用到的是Union Find, 即并查集。

并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

推荐一篇通俗易懂的文章: 傻子都能看懂的并查集入门

在这题中,我用了结构体代表每一条way,只是为了方便way的输入和储存,并查集相关的操作则用了数组的方式,也可以用结构体来表示city。

总体思路是:每次验证一个city,先把所有的city断开,再把和所要验证的city无关的其余city连接起来,就得到了几个连通图。之后检测一共有几个代表元,即有几个互不相连的连通图,总数减2就得到所要修建的道路总数。

以下是该题代码:

#include <iostream>
using namespace std;

int dadofcity[1000];  // 理解为树形结构中每个city的直接的父结点

int findpre(int x) {
    if (dadofcity[x] == x)
        return x;
/*

    else
        return findpre(dadofcity[x]);

    我一开始的代码是这样的,简单的递归,会导致超时,优化后为下面的代码,即在查找的同时,修改了该city的代表元,用时会大大缩短

*/
    else {
        int tmp = findpre(dadofcity[x]);
        dadofcity[x] = tmp;
        return tmp;
    }

}

void connnectcity(int x, int y) {
    int prex = findpre(x);
    int prey = findpre(y);
    if (prex != prey)
        dadofcity[prex] = prey;
}

struct way
{
    int x;
    int y;
};

way allway[500000];

int main() {
    int n, m, k;
    cin >> n >> m >> k;

    for (int i = 0; i < m; i++) {
        cin >> allway[i].x >> allway[i].y;
    }

    while (k--) {
        // disconnect all the cities
        for (int i = 1; i <= n; i++)
            dadofcity[i] = i;
        // connect cities except one
        int one;
        cin >> one;
        for (int i = 0; i < m; i++) {
            if (allway[i].x != one && allway[i].y != one)
                connnectcity(allway[i].x, allway[i].y);
        }
        int counter = 0;
        for (int i = 1; i <= n; i++)
            if (dadofcity[i] == i)
                counter++;

        cout << counter - 2 << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值