九度oj 题目1495:关键点
- 题目描述:
-
在一个无权图中,两个节点间的最短距离可以看成从一个节点出发到达另一个节点至少需要经过的边的个数。
同时,任意两个节点间的最短路径可能有多条,使得从一个节点出发可以有多条最短路径可以选择,并且沿着这些路径到达目标节点所经过的边的个数都是一样的。
但是在图中有那么一些特殊的节点,如果去除这些点,那么从某个初始节点到某个终止节点的最短路径长度要么变长,要么这两个节点变得不连通。这些点被称为最短路径上的关键点。
现给定一个无权图,以及起始节点和终止节点,要求输出该图上,这对节点间最短路径上的关键点数目。
- 输入:
-
输入包含多组测试数据,每组测试数据第一行为4个整数n(1<=n<=10000),m(1<=m<=100000),s(1<=s<=n),t(1<=t<=n)。分别代表该图中的节点个数n,边数量m,起始节点s,终止节点t。
接下去m行描述边的信息,每行两个整数a,b(1<=a,b<=n 且 a != b)。表示节点a和节点b之间有一条边。
- 输出:
-
对于每组测试数据,输出给定的这对节点间最短路径上的关键点数目。注意:若给定两个节点间不连通,则我们认为其关键点数目是0。
- 样例输入:
-
5 5 1 5
1 2
1 3
2 4
3 4
4 5
4 4 1 4
1 2
2 4
3 4
1 3
- 样例输出:
-
1
0 开始看到这个题觉得有些懵,
一开始用深度优先搜索来做,找到最短的那条路径,并且对路径上走过的每一个点进行计数
最后计数值和终点的计数值一致的点就是关键点
代码如下#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#define POINT_CNT 10020 using namespace std; vector <int> adj[POINT_CNT];
int flag[POINT_CNT];
int cnt[POINT_CNT];
int path[POINT_CNT];
int tm[POINT_CNT];
int n, m, s, t;
int minStep; void dfs(int from, int step) {
if (step > tm[from]) {
return;
}
if (from != s && step == tm[from]) {
if (cnt[from] != ) {
for (int j = ; j <= minStep; j++) {
cnt[path[j]]++;
tm[path[j]] = j;
}
}
return;
}
if (from == t) {
if (step < minStep) {
memset(cnt, , sizeof(cnt));
for (int j = ; j <= step; j++) {
cnt[path[j]] = ;
tm[path[j]] = j;
}
minStep = step;
}
else if (step == minStep) {
for (int j = ; j <= step; j++) {
cnt[path[j]]++;
tm[path[j]] = j;
}
}
return;
}
int sz = adj[from].size();
for (int i = ; i < sz; i++) {
int p = adj[from][i];
if (flag[p] == ) {
flag[p] = ;
path[step + ] = p;
dfs(p,step+);
flag[p] = ;
}
}
} int main() {
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout); while (scanf("%d %d %d %d", &n, &m, &s, &t) != EOF) {
for (int i = ; i < POINT_CNT; i++) {
adj[i].clear();
}
while (m--) {
int a, b;
scanf("%d %d", &a, &b);
adj[a].push_back(b);
adj[b].push_back(a);
}
memset(flag, , sizeof(flag));
memset(cnt, , sizeof(cnt));
for (int i = ; i <= n; i++) {
tm[i] = POINT_CNT;
}
minStep = POINT_CNT; flag[s] = ;
path[] = s;
tm[s] = ;
dfs(s,);
int way = cnt[t];
int ans = ;
if (way == ) {
puts("");
continue;
}
for (int i = ; i <= n; i++) {
if (cnt[i] == way && i != t) {
ans++;
}
}
printf("%d\n", ans);
}
return ;
}中间又做了一些剪枝的处理,但提交了好几次均超时。
无奈之下考虑广度优先搜索的思路
主要问题是如何找到关键点,此处我们需要遍历两次
第一次从源点s遍历到终点t,记录每一个经过点的层数
第二次从终点t遍历到起点s,只遍历那些层数比其小的。当队列为空时那个出队列的点就是关键点。
但一开始提交又是错误
代码如下
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue> #define POINT_CNT 10020 using namespace std; vector <int> edge[POINT_CNT];
int flag[POINT_CNT];
int level[POINT_CNT];
int n, m, s, t;
int minStep;
queue <int> que; int main() {
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout); while (scanf("%d %d %d %d", &n, &m, &s, &t) != EOF) {
for (int i = ; i < POINT_CNT; i++) {
edge[i].clear();
}
while (m--) {
int a, b;
scanf("%d %d", &a, &b);
edge[a].push_back(b);
edge[b].push_back(a);
}
if (n == ) {
puts("");
continue;
}
memset(flag, , sizeof(flag));
memset(level, , sizeof(level));
while (!que.empty()) {
que.pop();
}
que.push(s);
flag[s] = ;
while (!que.empty()) {
int p = que.front(); que.pop();
int ps = edge[p].size();
int step = level[p]; if (p == t) {
break;
}
for (int i = ; i < ps; i++) {
int to = edge[p][i];
if (flag[to] == ) {
que.push(to);
level[to] = step + ;
flag[to] = ;
}
}
} while (!que.empty()) {
que.pop();
}
que.push(t);
int ans = ;
while (!que.empty()) {
int p = que.front(); que.pop();
int ps = edge[p].size();
int step = level[p];
if (p == s) {
break;
}
if (que.empty()) {
ans++;
}
for (int i = ; i < ps; i++) {
int to = edge[p][i];
if (level[to] < step) {
que.push(to);
}
}
}
printf("%d\n", ans-);
}
return ;
}此时考虑特殊情况,如果只有一个点怎么办?如果有重边怎么办?
一是输出0,二是增加标记是否访问过
修改代码如下
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue> #define POINT_CNT 10020 using namespace std; vector <int> edge[POINT_CNT];
int flag[POINT_CNT];
int level[POINT_CNT];
int n, m, s, t;
int minStep;
queue <int> que; int main() {
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout); while (scanf("%d %d %d %d", &n, &m, &s, &t) != EOF) {
for (int i = ; i < POINT_CNT; i++) {
edge[i].clear();
}
while (m--) {
int a, b;
scanf("%d %d", &a, &b);
edge[a].push_back(b);
edge[b].push_back(a);
}
if (n == ) {
puts("");
continue;
}
memset(flag, , sizeof(flag));
memset(level, , sizeof(level));
while (!que.empty()) {
que.pop();
}
que.push(s);
flag[s] = ;
while (!que.empty()) {
int p = que.front(); que.pop();
int ps = edge[p].size();
int step = level[p]; if (p == t) {
break;
}
for (int i = ; i < ps; i++) {
int to = edge[p][i];
if (flag[to] == ) {
que.push(to);
level[to] = step + ;
flag[to] = ;
}
}
} while (!que.empty()) {
que.pop();
}
que.push(t);
int ans = ;
memset(flag, , sizeof(flag));
flag[t] = ;
while (!que.empty()) {
int p = que.front(); que.pop();
int ps = edge[p].size();
int step = level[p];
if (p == s) {
break;
}
if (que.empty()) {
ans++;
}
for (int i = ; i < ps; i++) {
int to = edge[p][i];
if (level[to] < step && flag[to]==) {
que.push(to);
flag[to] = ;
}
}
}
printf("%d\n", ans-);
}
return ;
}提交,还是错误。
。。。。。。。。。。
。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。
总是不过真是令人无奈
偶然发现自己初始化 level为0
那么有些和终点相连却并不和起点相连的点就会被访问,导致错误
比如
6就会被访问
再次修改如下
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue> #define POINT_CNT 10020 using namespace std; vector <int> edge[POINT_CNT];
int flag[POINT_CNT];
int level[POINT_CNT];
int n, m, s, t;
int minStep;
queue <int> que; int main() {
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout); while (scanf("%d %d %d %d", &n, &m, &s, &t) != EOF) {
for (int i = ; i < POINT_CNT; i++) {
edge[i].clear();
}
while (m--) {
int a, b;
scanf("%d %d", &a, &b);
edge[a].push_back(b);
edge[b].push_back(a);
}
memset(flag, , sizeof(flag));
fill(level, level + POINT_CNT, POINT_CNT);
while (!que.empty()) {
que.pop();
}
que.push(s);
level[s] = ;
flag[s] = ;
while (!que.empty()) {
int p = que.front(); que.pop();
int ps = edge[p].size();
int step = level[p]; if (p == t) {
break;
}
for (int i = ; i < ps; i++) {
int to = edge[p][i];
if (flag[to] == ) {
que.push(to);
level[to] = step + ;
flag[to] = ;
}
}
} while (!que.empty()) {
que.pop();
}
que.push(t);
int ans = ;
memset(flag, , sizeof(flag));
flag[t] = ;
while (!que.empty()) {
int p = que.front(); que.pop();
int ps = edge[p].size();
int step = level[p];
if (p == s) {
break;
}
if (que.empty()) {
ans++;
}
for (int i = ; i < ps; i++) {
int to = edge[p][i];
if (level[to] < step && flag[to]==) {
que.push(to);
flag[to] = ;
}
}
}
printf("%d\n", max(ans-,));
}
return ;
}提交终于通过了,
汗!!!!!!!!!!!!!!!!!!
九度oj 题目1495:关键点的更多相关文章
- 九度OJ 题目1384:二维数组中的查找
/********************************* * 日期:2013-10-11 * 作者:SJF0115 * 题号: 九度OJ 题目1384:二维数组中的查找 * 来源:http ...
- hdu 1284 关于钱币兑换的一系列问题 九度oj 题目1408:吃豆机器人
钱币兑换问题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 九度oj题目&吉大考研11年机试题全解
九度oj题目(吉大考研11年机试题全解) 吉大考研机试2011年题目: 题目一(jobdu1105:字符串的反码). http://ac.jobdu.com/problem.php?pid=11 ...
- 九度oj 题目1007:奥运排序问题
九度oj 题目1007:奥运排序问题 恢复 题目描述: 按要求,给国家进行排名. 输入: 有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号 ...
- 九度oj 题目1087:约数的个数
题目链接:http://ac.jobdu.com/problem.php?pid=1087 题目描述: 输入n个整数,依次输出每个数的约数的个数 输入: 输入的第一行为N,即数组的个数(N<=1 ...
- 九度OJ题目1105:字符串的反码
tips:scanf,cin输入字符串遇到空格就停止,所以想输入一行字符并保留最后的"\0"还是用gets()函数比较好,九度OJ真操蛋,true?没有这个关键字,还是用1吧,还是 ...
- 九度oj题目1009:二叉搜索树
题目描述: 判断两序列是否为同一二叉搜索树序列 输入: 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接 ...
- 九度oj题目1002:Grading
//不是说C语言就是C++的子集么,为毛printf在九度OJ上不能通过编译,abs还不支持参数为整型的abs()重载 //C++比较正确的做法是#include<cmath.h>,cou ...
- 九度OJ题目1003:A+B
while(cin>>str1>>str2)就行了,多简单,不得不吐槽,九度的OJ真奇葩 题目描述: 给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号", ...
随机推荐
- Elasticsearch 聚合操作
数据准备: PUT /shop { "settings": { "number_of_shards": 3, "number_of_replicas& ...
- [转]MySQL常用字符串函数
本文转载自:http://www.cnblogs.com/geaozhang/ 是最常用的的一种函数,在一个具体应用中通常会综合几个甚至几类函数来实现相应的应用: 1.LOWER(column|str ...
- php ecshop 二级域名切换跳转时session不同步,解决session无法共享同步导致无法登陆或者无法退出的问题
echshop基础上做了单点登录的 一级域名与二级域名 退出时 清空session 都是一级域名的session 因为二级域名的session是设置在二级域名上的 echshop基础上没有做单点登录的 ...
- 大数据&人工智能&云计算
仅从技术上讲大数据.人工智能都包含工程.算法两方面内容: 一.大数据: 工程: 1)云计算,核心是怎么管理大量的计算机.存储.网络. 2)核心是如何管理数据:代表是分布式存储,HDFS 3)核心是如何 ...
- C语言自问自答
Windows系统下,最好如何配置环境? notepad++,tdm-gcc,powershell来进行! scanf函数的返回值,和不符合格式如何返回? #include<stdio.h> ...
- NUCLEO-L053R8 RCC时钟树 MCO输出
RCC时钟配置实验 最近玩了一下Nucleo-L053R8板子,即STM32L053R8T6.浏览了RCC章节后,顺便做了个小实验,现在给大伙分享一下. 实验非常简单,配置一下系统时钟,可以通过肉眼观 ...
- Python 入门(一)
IDE 个人推荐 Pycharm : 比较好用,虽然没有中文,但是练练英语也不错,毕竟大同小异 基础语法 行与缩进 python最具特色的就是使用缩进来表示代码块,不需要使用大括号 {} . 缩进的 ...
- Windows下MySQL多实例运行(转)
关键字:Windows下MySQL多实例运行 阅读前注意事项: 1.有的版本的data目录不直接放在mysql安装目录下,有可能在:C:\ProgramData\MySQL\MySQL Server ...
- 青岛Uber优步司机奖励政策(1月4日~1月10日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 【机器学习笔记】EM算法及其应用
极大似然估计 考虑一个高斯分布\(p(\mathbf{x}\mid{\theta})\),其中\(\theta=(\mu,\Sigma)\).样本集\(X=\{x_1,...,x_N\}\)中每个样本 ...