修路
听说是学校原创的。
题目大意
公园里有一些地方,有些有路相连。公园经理需要修建一些旅游线路,他想安排旅游线路成一个环。如果一条铁路属于两个及以上的旅游线路,就有可能发生冲突,如果一条铁路不属于旅游线路,就不需要修建。 现在我们知道这个计划了,你能告诉我们有多少铁路不需要修建,有多少铁路可能发生冲突吗?
问有多少铁路不需要修建,有多少铁路可能发生冲突吗?
解题思路
首先,对于第一个问题:
如果一条铁路不在环里面,就不需要修建,问有多少铁路不需要修建。
其实就是求 桥 的数量。
再看第二个问题:
如果一条铁路属于一条以上的旅游线路,就有可能发生冲突,问有多少铁路可能发生冲突。
对于这个问题,我们首先思考怎么判断一条铁路是否在多个环内。
先看样例,如下:
输入
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
显然,边双连通分量是 和 。
可以发现, 条可能发生冲突的铁路都是边双连通分量 里的边。
思考,为什么 和 同为边双连通分量,为什么只有一个是答案呢?
显然可以发现, 除了普通的 条边:
,,,。
还多出一条不寻常的边 ,把原图分成 个环 :
,,。
为了更好地发现问题,再来一组数据,如下:
输入
6 7
0 1
1 2
2 3
3 0
2 5
3 4
5 4
0 0
输出
0 7
显然,所有边都是答案。
综上,可以得出一个结论:
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;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122140
分类:
个人记录
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话