PAT-A 1013. Battle Over Cities (25)

  1. Battle Over Cities (25)

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue
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


题目大意:有n个城市,城市之间有m条路,有k个城市被敌军占领(注意,这里不是同时占领,而是每次占领只是这k个城市中的一个)。求出如果要让除了被占领的城市以外所有剩余的城市能相互连通,还需要修几条路。

分析:
这是一个判断图连通的问题,用并查集将相邻的点加入同一个集合,最后如果有n个集合,则还需要修n-1条路

这里注意的是每一次要把敌军占领的城市排除在外。

我使用了邻接链表存储了无向图,对于每一个敌军占领的城市的case,都需要重新计算一遍,我觉得这里是可以优化的,因为对于不同的敌军,除了其占领的城市及其邻边外,其他的点之间的连通关系是已知的了。

#include<stdio.h>
#include<vector>
using namespace std;

struct Edge{
  int next;
};

vector<Edge> edge[1000];

int root[1000];
int result;
int n,m,k;

int findRoot(int x){        //找到根节点,并优化路径,使所有同一集合中的点都指向该根节点,这样在以后查找根节点时,仅需要O(1)的时间
  if(root[x] == -1) return x;
  else{
    root[x] = findRoot(root[x]);
    return root[x];
  }
}

int main(){
  int a,b;
  scanf("%d%d%d", &n,&m,&k);

  for(int i=1; i<=n; i++){      //初始化
    root[i] = -1;
    edge[i].clear();
  }

  Edge tmp;              //存储图,无向图
  for(int i=1; i<=m; i++){
    scanf("%d%d",&a,&b);
    tmp.next = a;
    edge[b].push_back(tmp);
    tmp.next = b;
    edge[a].push_back(tmp);
  }

  int nPoint, jPoint,enermy;          //分别为当前点,相邻点,敌人占据点
  for(int i=1;i<=k;i++){
    scanf("%d", &enermy);

    for(int j=1; j<=n ; j++){  //遍历所有的点的邻边
      if( j == enermy) continue;
      for(int jj=0; jj<edge[j].size(); jj++){
        if(edge[j][jj].next != enermy){
        //并查集
          nPoint = findRoot(j);
          jPoint = findRoot(edge[j][jj].next);
          if(nPoint != jPoint)
            root[jPoint] = nPoint;

        }
      }
    }
    result = 0;
    for(int j=1; j<=n; j++){
      if( root[j] == -1){    //遍历所有节点,统计根节点的数量
        result++;
      }
      root[j] = -1;          //访问过后还原成-1,相当于下一次求解的初始化
    }
    result -= 2;            //因为把enermy点也算进去了(显然它是一个根节点),所以要-2
    printf("%d\n", result);
  }

  return 0;
}

总结:
1.并查集的优化要牢记
2.无向图存储时要注意要加入两个点的邻接链表中
3.今晚的时间浪费在了存储邻接链表上,符号打错了。时间就是生命,一点要细心!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值