1013 Battle Over Cities (25分) PAT

方案一

记录所有的边(可以用邻接表)
    对每个丢失的城市(每个查询)
        根据边,用并查集对城市进行集合的合并  O(e)
        检查一共有n个集合,则需要修n-1条路   O(v)

代码如下:

#include<cstdio>
#include<vector>
#include<set>

using namespace std;
const int maxn = 1010;

int findfather(int father[], int a) {
    int x = a;
    while (x != father[x]) {
        x = father[x];
    }
    int temp;
    while (father[a] != x) {
        temp = father[a];
        father[a] = x;
        a = temp;
    }
    return x;
}

int main() {
    int N, M, K;
    int a, b;  // two cities the highway connect
    int c; // the lost city
    vector<int> node[maxn];
    scanf("%d %d %d", &N, &M, &K);
    for (int m = 0; m < M; m++) {
        scanf("%d %d", &a, &b);
        node[a].push_back(b);
        // node[b].push_back(a);  // it is not neccisery if using union set
    }
    int father[maxn];

    for (int k = 0; k < K; k++) {
        scanf("%d", &c);
        for (int i = 1; i <= N; i++) {
            father[i] = i;
        }
/*
        // test
        for (int i = 1; i <= 10; i++) {
            printf("%d ", father[i]);
        }
        printf("\n");
*/
        for (int i = 1; i <= N; i++) {
            if (i == c) continue;
            int fa = findfather(father, i);
            for (int j = 0; j < node[i].size(); j++) {
                if (node[i][j] == c) continue;
                int fb = findfather(father, node[i][j]);
                if (fa != fb) {
                    father[fb] = fa;

//                    // test
//                    for (int i = 1; i <= 10; i++) {
//                        printf("%d ", father[i]);
//                    }
//                    printf("\n");
                }
            }
        }
        set<int> countSet;
        for (int i = 1; i <= N; i++) {
            if (i == c) continue;
            countSet.insert(findfather(father, i));
        }
        printf("%d\n", countSet.size() - 1);
    }

    return 0;
}

方案二

用邻接矩阵存储图(或者用邻接表)
    对每个丢失的城市
    根据图采用宽度(或深度)优先搜索,记录需要多少次搜索(即产生多少搜索树)

两个的复杂度应该都是O(v+e),其中v为顶点的数目,e为边的数目

代码如下:

其中,需要注意的是:visit 数组在DFS中表示“该结点是否被访问过”,而在BFS中表示“该结点是否进入过队列”,如果BFS中的定义与DFS中相同,则在PAT测试中,最后一个测试样例超时。原因是定义为“是否被访问过”将导致已经进入队列,但是没有被访问过的结点再次进入队列,从而产生重复,导致超时。

#include<cstdio>
#include<vector>
#include<set>
#include<queue>

using namespace std;
const int maxn = 1010;

void DFS(int i, vector<int> node[], bool visit[], int c) {
    if (visit[i] == true) return;
    else {
        visit[i] = true;
        if(node[i].size() == 0) return;
        for (int j = 0; j < node[i].size(); j++) {
            if (node[i][j] == c) continue;
            DFS(node[i][j], node, visit, c);
        }
    }
    return;
}

void BFS(int i, vector<int> node[], bool visit[], int c) {
    queue<int> q;
    q.push(i);
    visit[i] = true;
    while(!q.empty()) {
        int temp = q.front();
        q.pop();
        for (int j = 0; j < node[temp].size(); j++) {
            int temp2 = node[temp][j];
            if (temp2 != c && visit[temp2] != true) {
                q.push(temp2);
                visit[temp2] = true;
            }

        }
    }
}

int main() {
    int N, M, K;
    int a, b;  // two cities the highway connect
    int c; // the lost city
    vector<int> node[maxn];
    scanf("%d %d %d", &N, &M, &K);
    for (int m = 0; m < M; m++) {
        scanf("%d %d", &a, &b);
        node[a].push_back(b);
        node[b].push_back(a);
    }

    for (int k = 0; k < K; k++) {
        scanf("%d", &c);
        int countTimes = 0;
        bool visit[maxn] = {false};
        for (int i = 1; i <= N; i++) {
            if (i == c) continue;
            if (!visit[i]) {
                countTimes++;
                BFS(i, node, visit, c);  // change the "BFS" to "DFS" will use the DFS method
            }
        }
        printf("%d\n", countTimes - 1);
    }

    return 0;
}
发布了17 篇原创文章 · 获赞 0 · 访问量 2438

猜你喜欢

转载自blog.csdn.net/Ike_Lin/article/details/104532750