PAT A1013 Battle Over Cities (25分)


图的实现方式主要有两种:1.邻接表 2.邻接矩阵
邻接矩阵在顶点数目大于1000的情况就基本不适用了,而邻接表的链表实现在考试中代码量偏大
所以采取变成数组构建邻接表可以简化程序书写
邻接表的表示为:vector G[N];
当然本题还可以利用并查集的数据结构完成快速合并与查询,见代码2,但其实不建议使用并查集,因为并查集虽然容易确定是否连通但是最大的缺点就是很难删除,为了完成删除k次的操作
只能在每次查询阶段建立并查集,没有DFS和BFS来的简便和明显
注意:

  1. 使用并查集必须进行路径压缩否则会导致数据超时
  2. 由于是无向图,在读入数据两个方向的边都需要存储
    代码1:邻接表+DFS
#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
const int N = 1010;
vector<int> G[N];//从1开始
bool vis[N];//从1开始

void DFS(int a,int check){
    if(a==check||vis[a]==true) return;
    else{
        vis[a] = true;
        for(int i = 0;i<G[a].size();i++){
                DFS(G[a][i],check);
        }
        return;
    }
}
int main(){
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 0;i< m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
    int check;
    for(int i = 0 ; i < k;i++){//k次查询
        scanf("%d",&check);
        memset(vis,false,sizeof(vis));
        int block = 0;//连通块个数
        for(int j = 1; j <= n;j++){
            if(j!=check&&vis[j]==false){
                DFS(j,check);
                block++;
            }
        }
        printf("%d",block-1);
            
        if(i < k-1) printf("
");
    }
    return 0;
}

代码2:邻接表+并查集

#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
const int N = 1010;
vector<int> G[N];//从1开始
bool vis[N];//从1开始
int father[N];//从1开始

void init(int n){//从1到n
    for(int i = 1;i<=n;i++){
        father[i] = i;
        vis[i] = false;
    }
    return;
}

int findFather(int x){
    int a = x;
    while(x!=father[x]){
        x = father[x];
    }
    //路径压缩
    while(a!=father[a]){
        int z = a;
        a = father[a];
        father[z] = x;
    }
    return x;
}

void Union(int a,int b){
    int fa = findFather(a);
    int fb = findFather(b);
    if(fa!=fb) father[fa] = fb;
    return;
}
int main(){
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 0;i< m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
    int check;
    for(int i = 0 ; i < k;i++){//k次查询
        scanf("%d",&check);
        init(n);
        //建立当前并查集
        for(int j = 1; j <= n;j++){
            if(j!=check){
                for(int d = 0;d<G[j].size();d++){
                    if(G[j][d]!=check){
                        int v = G[j][d];
                        int u = j; 
                        Union(v,u);
                    }
                }
            }                
        }
        int block = 0;//连通块个数
        for(int j = 1;j <= n;j++){//遍历n个结点
            if(j != check){
                int fa = findFather(j);
                if(vis[fa]==false){
                    block++;
                    vis[fa] = true;
                }
            }
        }
        
        printf("%d",block-1);
            
        if(i < k-1) printf("
");
   }
        
        
    
    return 0;
}
原文地址:https://www.cnblogs.com/shuibeng/p/13572003.html