PAT (Advanced Level) Practice1013 Battle Over Cities (25 分)(Java)

52 篇文章 0 订阅
51 篇文章 0 订阅

全部答案(持续更新)

Problem Description

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 c i t y 1 − c i t y ​ 2 city_1 - city​_2 city1city2​​ and c i t y ​ 1 ​ ​ − c i t y ​ 3 city​_1​​ - city_​3 city1city3#​ . Then if c i t y ​ 1 city​_1 city1​​ is occupied by the enemy, we must have 1 highway repaired, that is the highway c i t y ​ 2 − c i t y ​ 3 city​_2 - city​_3 city2city3​​ .

Input Specification:

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 Specification:

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

Code Example(DFS, time-out)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * @author snowflake
 * @create-date 2019-08-28 17:03
 */
public class Main {

    public static void main(String[] args) throws IOException {
        Reader.init(System.in);
        int n = Reader.nextInt();
        int m = Reader.nextInt();
        int k = Reader.nextInt();
        // 创建 n * n 的二维数组
        int[][] cities = new int[n][n];
        for (int i = 0; i < m; i++) {
            int n1 = Reader.nextInt();
            int n2 = Reader.nextInt();
            cities[n1 - 1][n2 - 1] = 1;
            cities[n2 - 1][n1 - 1] = 1;
        }
        for (int i = 0; i < k; i++) {
            int index = Reader.nextInt();
            // 然后判断该图有几个连通子图
            System.out.println(method1(index - 1, cities) - 1);
        }
    }

    public static int method1(int index, int[][] cities) {
        int num = 0;
        // 定义一个访问标记数组
        boolean[] visited = new boolean[cities.length];
        // 标记破坏点已经访问过
        visited[index] = true;
        // 开始遍历
        for (int i = 0; i < cities.length; i++) {
            if (!visited[i]) {
                // 提前标记访问过,这样不同在 dfs 方法中跳过该点
                visited[i] = true;
                dfs(cities, i, visited);
                num++;
            }
        }
        return num;
    }

    private static void dfs(int[][] cities, int i, boolean[] visited) {
        // 纠结为什么要从 j = 0 从头开始,明明是无向图,直接从 i + 1 开始即可,
        // 但是忽略了一点,如果直接从 i + 1 开始的话,会失去部分指向关系,
        // 导致一个无向图变成了一个有向图
        // 如果是有向图,从不同的顶点进行遍历,得到的结果是不一样的
        // 后来想了一下,是从第一行开始遍历的那么,左下角的元素肯定是访问过的,例如
        // 0 1 1 1
        // 1 0 1 1
        // 1 1 0 1
        // 1 1 1 0
        // 这种情况下如果不从 0 开始遍历,是成功的但是
        // 0 0 0 1
        // 0 0 1 1
        // 0 1 0 0
        // 1 1 0 0
        // 这种情况下,访问到 [0, 3] 会跳转到 第四行,但是第四行跟第二行还有指向关系,
        // 但是如果不从 0 开始遍历的话,就无法取到这个指向关系了,那么会多出一个连通分支
        for (int j = 0; j < cities.length; j++) {
            if (!visited[j] && cities[i][j] == 1) {
                visited[j] = true;
                dfs(cities, j, visited);
            }
        }
    }


    static class Reader {

        static BufferedReader reader;
        static StringTokenizer tokenizer;

        /**
         * call this method to initialize reader for InputStream
         */
        public static void init(InputStream input) {
            reader = new BufferedReader(new InputStreamReader(input));
            tokenizer = new StringTokenizer("");
        }

        public static String nextLine() throws IOException {
            return reader.readLine();
        }

        /**
         * get next word
         */
        public static String next() throws IOException {
            while (!tokenizer.hasMoreTokens()) {
                tokenizer = new StringTokenizer(reader.readLine());
            }
            return tokenizer.nextToken();
        }

        public static int nextInt() throws IOException {
            return Integer.parseInt(next());
        }

        public static double nextDouble() throws IOException {
            return Double.parseDouble(next());
        }

    }

}

Code Example(DisjointUnionSets, time-out)

package xyz.snowflake.arithmetic.disjoint_set;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @create-date 2019-08-29 22:10
 */
// A Java program to implement Disjoint Set Data
// Structure.
class DisjointUnionSets {
    int[] rank, parent;
    int n;

    // Constructor
    public DisjointUnionSets(int n) {
        rank = new int[n];
        parent = new int[n];
        this.n = n;
        makeSet();
    }

    // Creates n sets with single item in each
    void makeSet() {
        for (int i = 0; i < n; i++) {
            // Initially, all elements are in
            // their own set.
            parent[i] = i;
        }
    }

    // Returns representative of x's set
    int find(int x) {
        // Finds the representative of the set
        // that x is an element of
        if (parent[x] != x) {
            // if x is not the parent of itself
            // Then x is not the representative of
            // his set,
            parent[x] = find(parent[x]);

            // so we recursively call Find on its parent
            // and move i's node directly under the
            // representative of this set
        }

        return parent[x];
    }

    // Unites the set that includes x and the set
    // that includes x
    void union(int x, int y) {
        // Find representatives of two sets
        int xRoot = find(x);
        int yRoot = find(y);

        // Elements are in the same set, no need
        // to unite anything.
        if (xRoot == yRoot)
            return;

        // If x's rank is less than y's rank
        if (rank[xRoot] < rank[yRoot])

            // Then move x under y  so that depth
            // of tree remains less
            parent[xRoot] = yRoot;

            // Else if y's rank is less than x's rank
        else if (rank[yRoot] < rank[xRoot])

            // Then move y under x so that depth of
            // tree remains less
            parent[yRoot] = xRoot;

            // if ranks are the same
        else {
            // Then move y under x (doesn't matter
            // which one goes where)
            parent[yRoot] = xRoot;

            // And increment the the result tree's
            // rank by 1
            rank[xRoot] = rank[xRoot] + 1;
        }
    }
}

public class Main {

    static class Node {
        int n1, n2;

        public Node(int n1, int n2) {
            this.n1 = n1;
            this.n2 = n2;
        }
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int m = cin.nextInt();
        int k = cin.nextInt();
        List<Node> list = new ArrayList<>(n);
        for (int i = 0; i < m; i++) {
            int n1 = cin.nextInt();
            int n2 = cin.nextInt();
            list.add(new Node(n1 - 1, n2 - 1));
        }
        for (int i = 0; i < k; i++) {
            int value = cin.nextInt();
            List<Node> filterList = new ArrayList<>();
            for (Node node : list) {
                if (node.n1 != value - 1 && node.n2 != value - 1) {
                    filterList.add(node);
                }
            }
            DisjointUnionSets dus = new DisjointUnionSets(n);
            for (Node node : filterList) {
                dus.union(node.n1, node.n2);
            }
            int count = 0;
            for (int j = 0; j < n; j++) {
                if (dus.find(j) == j) {
                    count++;
                }
            }
            System.out.println(n == 1 ? 0 : count - 2);
        }
    }

}

Code Example(C++, success)

#include<cstdio>
#include<cstring>
 
int N, M, lost;
bool map[1000][1000], visited[1000];
 
void dfs(int start)
{
    for(int i = 1; i <= N; ++i)
    {
        if(!visited[i] && map[start][i])
        {
            visited[i] = true;
            dfs(i);
        }
    }
}
 
int main()
{
    int K, c1, c2, cnt;
    scanf("%d %d %d", &N, &M, &K);
    for(int i = 0; i < M; ++i)
    {
        scanf("%d %d", &c1, &c2);
        map[c1][c2] = map[c2][c1] = true;
    }
    for(int i = 0; i < K; ++i)
    {
        scanf("%d", &lost);
        cnt = 0;
        memset(visited, 0, sizeof(visited));
        visited[lost] = true;
        for(int j = 1; j<=N; ++j)
        {
            if(visited[j]==false)
            {
                ++cnt;
                dfs(j);
            }
        }
        printf("%d\n", cnt-1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值