1013. Battle Over Cities (25)
题目如下:
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
看到这个题目,我的第一想法是用DFS来处理,利用DFS以每个结点为起点进行搜索,找出不能访问到所有结点的结点,这些结点构成的独立区域便是那些需要额外修建公路的区域,但有个问题是如果独立区域有多个结点,在计数时会出现重复,但是可以发现,在对某个结点进行DFS时,所有和它连通的结点都被访问到了,因此不必担心重复计数的问题。最后独立区域的个数-1即为要修建公路的条数。
- #include<stdio.h>
- #include<string.h>
- #define max 1001
- int edge[max][max];
- int visited[max];
- int N, M, K;
- void DFS(int start)
- {
- visited[start] = 1;
- int i;
- for (i = 1; i <= N; i++)
- {
- if (!visited[i] && edge[i][start] == 1)
- DFS(i);
- }
- }
- int main()
- {
- int i, j;
- int a, b;
- scanf("%d%d%d", &N, &M, &K);
- for (i = 0; i<M; i++)
- {
- scanf("%d%d", &a, &b);
- edge[a][b] = 1;
- edge[b][a] = 1;
- }
- int temp;
- int num;
- for (i = 0; i<K; i++)
- {
- num = 0;
- scanf("%d", &temp);
- memset(visited, 0, sizeof(visited));
- visited[temp] = 1;
- for (j = 1; j <= N; j++)
- {
- if (visited[j] == 0)
- {
- DFS(j);
- num++;
- }
- }
- if (num == 0) printf("0\n");
- else printf("%d\n", num - 1);
- }
- }
另外一种方法是使用并查集,将所有有边的结点并入同一个集合,并且在查找父节点时进行路径压缩,保证在一个集合中的所有父节点均指向祖先节点,这时候只要计数祖先节点的数目,就可以找出独立区域的个数。
这个方法是从sunbaigui的博客上学到的,下面是他的算法,我在理解的基础上加了些注释,方便阅读。
- #include<iostream>
- #include<vector>
- #include<set>
- #include<map>
- #include<queue>
- #include<algorithm>
- #include<string>
- #include<string.h>
- using namespace std;
- int n;//number of city
- int m;//number of edge
- int k;//number of query
- typedef struct Edge
- {
- int v;
- Edge(int _v) :v(_v){};
- }Edge;
- typedef struct Node
- {
- int parent;
- }Node;
- vector<Node> city;
- void InitSet()
- {
- city.resize(n); // 使用vector的resize方法可以重设vector大小
- for (int i = 0; i < n; ++i)
- city[i].parent = i; // 初始化每个人的父节点为自己
- }
- void CompressSet(int top, int x) // 压缩路径的目的是让x的父节点指向top
- {
- if (city[x].parent != top) // 如果x的父节点不指向top,应当让它指向top,注意x的父节点和之前的路径也要压缩,因此先递归再赋值。
- {
- CompressSet(top, city[x].parent); // 继续向上压缩
- city[x].parent = top; // 调整父节点为top
- }
- }
- int FindSet(int x) // 找到x的父节点,并且在寻找之前压缩路径
- {
- if (city[x].parent != x) // 如果x的父节点不是自己,说明这个集合不是单个元素的集合,应该把所有元素指向祖先节点。
- {
- int top = FindSet(city[x].parent); // 先获取集合的祖先节点
- CompressSet(top, x); // 压缩x到祖先路径上的所有结点指向top
- }
- return city[x].parent; // 如果x的父节点为自己,说明这就是祖先节点。
- }
- void UnionSet(int x, int y)
- {
- int a = FindSet(x);
- int b = FindSet(y);
- city[a].parent = b; // 集合的合并即找到二者的父亲,让其中一个的父亲成为另一个结点,因为这里不涉及到计数,因此不必判断集合大小。
- }
- int main()
- {
- //input
- scanf("%d%d%d", &n, &m, &k);
- vector<vector<Edge>> edge;
- edge.resize(n);
- for (int i = 0; i < m; ++i)
- {
- int a, b;
- scanf("%d%d", &a, &b);
- a--; b--;
- edge[a].push_back(Edge(b));
- edge[b].push_back(Edge(a));
- }
- //
- //query
- for (int i = 0; i < k; ++i)
- {
- int q;
- scanf("%d", &q);
- q--;
- InitSet(); // 每个元素都是祖先
- for (int u = 0; u < n; ++u)
- {
- for (int j = 0; j < edge[u].size(); ++j)
- {
- int v = edge[u][j].v;
- if (u != q&&v != q) UnionSet(u, v); // 把v w结点的集合合并
- }
- }
- // 这时候所有结点都加入了集合,但是注意到还没有压缩路径,因此很多结点的父节点并未成功指向祖先节点。
- set<int> parentSet;
- for (int j = 0; j < n; ++j){
- // 为了保证所有结点指向祖先结点,使用FindSet函数来查找parent,而不能直接获取parent成员变量,一定要注意!
- parentSet.insert(FindSet(j)); // 由于没有排除被占领的结点自成一个父节点,故要减去它才是真正的所有未占领结点组成的集合。
- }
- printf("%d\n", parentSet.size() - 2);
- }
- return 0;
- }
1013. Battle Over Cities (25)的更多相关文章
- PAT 解题报告 1013. Battle Over Cities (25)
1013. Battle Over Cities (25) t is vitally important to have all the cities connected by highways in ...
- PAT 甲级 1013 Battle Over Cities (25 分)(图的遍历,统计强连通分量个数,bfs,一遍就ac啦)
1013 Battle Over Cities (25 分) It is vitally important to have all the cities connected by highway ...
- 1013 Battle Over Cities (25分) DFS | 并查集
1013 Battle Over Cities (25分) It is vitally important to have all the cities connected by highways ...
- PAT A 1013. Battle Over Cities (25)【并查集】
https://www.patest.cn/contests/pat-a-practise/1013 思路:并查集合并 #include<set> #include<map> ...
- 1013 Battle Over Cities (25)(25 point(s))
problem It is vitally important to have all the cities connected by highways in a war. If a city is ...
- 1013. Battle Over Cities (25)(DFS遍历)
For example, if we have 3 cities and 2 highways connecting city1-city2 and city1-city3. Then if city ...
- PAT Advanced 1013 Battle Over Cities (25) [图的遍历,统计连通分量的个数,DFS,BFS,并查集]
题目 It is vitally important to have all the cities connected by highways in a war. If a city is occup ...
- 1013 Battle Over Cities (25 分)
It is vitally important to have all the cities connected by highways in a war. If a city is occupied ...
- 1013 Battle Over Cities (25分) 图的连通分量+DFS
题目 It is vitally important to have all the cities connected by highways in a war. If a city is occup ...
随机推荐
- 模仿天猫实战【SSM版】——项目起步
前言:现在自己的学习似乎遇到了瓶颈,感觉学习了 SSM 之后有一些迷茫,不知道接下来该往哪里去努力了,我觉得这是个很不好的状态,为了度过这段时期,我准备把天猫模仿下来(给自己找点事做)之后开始去巩固 ...
- linux tar解压命令
linux下使用tar命令 解压语法:tar [主选项+辅选项] 文件或者目录 使用该命令时,主选项是必须要有的,它告诉tar要做什么事情,辅选项是辅助使用的,可以选用.主选项:c 创建新的档案文件. ...
- 有趣的冷知识:编程中Foo, Bar 到底什么意思?
转自:编程中Foo, Bar 到底什么意思? 1 前言 在很多国外计算机书本和一些第三份开源软件的Demo中经常用到两个英文单词Foo,Bar.这到底是什么意思呢?从步入屌丝界的IT生活见到这两个单词 ...
- JavaScript的BOM、DOM操作、节点以及表格(二)
BOM操作 一.什么是BOM BOM(Browser Object Model)即浏览器对象模型. BOM提供了独立于内容 而与浏览器窗口进行交互的对象: BOM由一系列相关的对象构成 ...
- java.lang.ClassCastException: oracle.sql.CLOB cannot be cast to oracle.sql.CLOB
错误现象: [framework] 2016-05-26 11:34:53,590 -INFO [http-bio-8080-exec-7] -1231863 -com.dhcc.base.db.D ...
- Python中的数据类型
计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据,需要定义不同的数 ...
- Mac下安装PEAR
The following instructions install PEAR and PECL on Mac OS X under/usr/local/. PECL is bundled with ...
- MySQL NOW() 函数
定义和用法 NOW() 返回当前的日期和时间. 语法 NOW() 实例 下面是 SELECT 语句: SELECT NOW(),CURDATE(),CURTIME() 结果如下所示: NOW() CU ...
- JAVA生成数字0~9字母A~Z混合编码0000、0001...0009、000A...000Z、0010......
分别是求下一个编码 和 输出所有编码 /** * 用1--9加A--Z混合编码 使用ASCII码判断 * LYL * 传一个值 求下一个编码 */ public String getABCDCode( ...
- Java内存泄漏分析系列之三:jstat命令的使用及VM Thread分析
原文地址:http://www.javatang.com 使用jstat命令 当服务器CPU100%的时候,通过定位占用资源最大的线程定位到 VM Thread: "VM Thread&qu ...