修路
时间:2021-08-11
本文章向大家介绍修路,主要包括修路使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
听说是学校原创的。
题目大意
公园里有一些地方,有些有路相连。公园经理需要修建一些旅游线路,他想安排旅游线路成一个环。如果一条铁路属于两个及以上的旅游线路,就有可能发生冲突,如果一条铁路不属于旅游线路,就不需要修建。
现在我们知道这个计划了,你能告诉我们有多少铁路不需要修建,有多少铁路可能发生冲突吗?
问有多少铁路不需要修建,有多少铁路可能发生冲突吗?
解题思路
首先,对于第一个问题:
如果一条铁路不在环里面,就不需要修建,问有多少铁路不需要修建。
其实就是求 桥 的数量。
再看第二个问题:
如果一条铁路属于一条以上的旅游线路,就有可能发生冲突,问有多少铁路可能发生冲突。
对于这个问题,我们首先思考怎么判断一条铁路是否在多个环内。
先看样例,如下:
输入
8 10
0 1
1 2
2 3
3 0
3 4
4 5
5 6
6 7
7 4
5 7
0 0
输出
1 5
显然,边双连通分量是 \([0,1,2,3]\) 和 \([4,5,6,7]\)。
可以发现,\(5\) 条可能发生冲突的铁路都是边双连通分量 \([4,5,6,7]\) 里的边。
思考,为什么 \([0,1,2,3]\) 和 \([4,5,6,7]\) 同为边双连通分量,为什么只有一个是答案呢?
显然可以发现,\([4,5,6,7]\) 除了普通的 \(4\) 条边:
\((4,5)\),\((5,6)\),\((6,7)\),\((7,4)\)。
还多出一条不寻常的边 \((5,7)\),把原图分成 \(3\) 个环 :
\((5,6,7)\),\((4,5,7)\),\((4,5,6,7)\)。
为了更好地发现问题,再来一组数据,如下:
输入
6 7
0 1
1 2
2 3
3 0
2 5
3 4
5 4
0 0
输出
0 7
显然,所有边都是答案。
综上,可以得出一个结论:
\[\color{red}{当一个双连通分量中的边数大于点数时,其中所有的边都属于两个及以上的环。}
\]
AC CODE
#include<bits/stdc++.h>
using namespace std;
struct Fastio
{
template <typename T>
inline Fastio operator>>(T &x)
{
x = 0;
char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return *this;
}
inline Fastio &operator<<(const char *str)
{
int cur = 0;
while (str[cur])
putchar(str[cur++]);
return *this;
}
template <typename T>
inline Fastio &operator<<(T x)
{
if (x == 0)
{
putchar('0');
return *this;
}
if (x < 0)
putchar('-'), x = -x;
static int sta[45];
int top = 0;
while (x)
sta[++top] = x % 10, x /= 10;
while (top)
putchar(sta[top] + '0'), --top;
return *this;
}
} io;
#define _ 200005
int n, m, ans1, ans2, ans3;
int tot, head[_], to[_ << 1], nxt[_ << 1];
int dol[_];
int cnt_node, cntn, low[_], dfn[_], id[_], siz1[_], siz2[_], vis[_ << 1], vs[_];
stack<int> s;
int bridge[_ << 1];
int u[_], v[_];
int js(int x)
{
return (x % 2) ? x + 1 : x - 1;
}
void add(int u, int v)
{
to[++tot] = v;
nxt[tot] = head[u];
head[u] = tot;
}
void tarjan(int u)
{
low[u] = dfn[u] = ++cnt_node;
s.push(u);
for(int i = head[u]; i; i = nxt[i])
if(!vis[i])
{
vis[i] = vis[js(i)] = 1;
if(!dfn[to[i]])
{
tarjan(to[i]);
low[u] = min(low[u], low[to[i]]);
if(low[to[i]] > dfn[u])
{
bridge[i] = bridge[js(i)] = 1;
}
}
else low[u] = min(low[u], dfn[to[i]]);
}
if(dfn[u] == low[u])
{
cntn++;
while(1)
{
int now = s.top();
s.pop();
id[now] = cntn;
siz1[cntn]++;
if(now == u) break;
}
}
}
void init()
{
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
ans1 = ans2 = ans3 = cnt_node = cntn = tot = 0;
memset(id, 0, sizeof id);
memset(siz1, 0, sizeof siz1);
memset(siz2, 0, sizeof siz2);
memset(vis, 0, sizeof vis);
memset(vs, 0, sizeof vs);
while(!s.empty()) s.pop();
memset(bridge, 0, sizeof bridge);
memset(head, 0, sizeof head);
}
void dfs(int x)
{
for(int i = head[x]; i; i = nxt[i])
{
int v = to[i];
if(dfn[i]) continue;
dfn[i] = 1;
if(bridge[i]) continue;
// cout << v << endl;
ans3++;
dfs(v);
}
}
signed main()
{
while(cin >> n >> m && n && m)
{
init();
for(int i = 1; i <= m; ++i)
{
io >> u[i] >> v[i];
u[i]++;
v[i]++;
add(u[i], v[i]);
add(v[i], u[i]);
}
for(int i = 1; i <= n; ++i)
if(!dfn[i]) tarjan(i);
for(int i = 1; i <= m; ++i)
if(bridge[i << 1]) ans1++;
memset(dfn, 0, sizeof dfn);
for(int i = 1; i <= m; ++i)
{
if(!dfn[i])
{
ans3 = 0;
dfs(u[i]);
siz2[id[i]] = ans3;
// cout << ans3 << endl;
}
}
// for(int i = 1; i <= cntn; ++i) cout << siz1[i] << " ";
// cout << endl;
// for(int i = 1; i <= cntn; ++i) cout << siz2[i] << " ";
// cout << endl;
for(int i = 1; i <= n; ++i)
{
if(!vs[id[i]] && siz2[id[i]] / 2 > siz1[id[i]])
{
ans2 += siz2[id[i]] / 2;
vs[id[i]] = 1;
}
}
io << ans1 << " " << ans2 << "\n";
}
return 0;
}
原文地址:https://www.cnblogs.com/orzz/p/15127385.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Docker私有镜像仓库是什么?
- React Native布局详细指南
- 走进Golang之Context的使用
- 「Workshop」第十一期:降维
- 开始在 GitHub 上写博客
- 微信公众号菜单点击发送天气预报
- SAP CRM Fiori应用如何启用Sales Office和Sales Group两个字段
- 通过注册表调整 Windows 8 窗口边框宽度
- 在 Mac OS X 中创建和使用内存盘
- Mono for Android 下的 ListActivity
- 使用JavaScript Function.prototype进行代码重构的一些例子
- Activity 生命周期及其栈管理方式
- 如何操作SAP UI5应用Footer区域工具栏按钮的背景颜色
- 我的第一个 Mono for Android 应用
- 【DB笔试面试851】在Oracle中,造成“ORA-28040: No matching ...”错误的原因是什么?