专栏文章
题解:AT_abc280_f [ABC280F] Pay or Receive
AT_abc280_f题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mip8dqbk
- 此快照首次捕获于
- 2025/12/03 07:50 3 个月前
- 此快照最后确认于
- 2025/12/03 07:50 3 个月前
题目大意
有一张有向图,其中 个顶点, 条边。第 条边连接 和 ,其中从 到 的权值为 ,从 到 的权值为 。给出 个问题:
- 从 到 时的最大得分。
- 如果 与 不在一个子图里,输出
nan。 - 如果 到 的分数可以是无限,输出
inf。
注:本题解的子图可以理解为强连通分量。
思路
分析
这是最长路问题,根据题意,输出有 种情况。
- 第一种情况:需 与 在同一子图中。
- 第二种情况: 与 不在同一子图,输出
nan。 - 第三种情况:子图存在正环,输出
inf。
解法
首先我们需要了解图的两个知识。
- 如下图,我们举个例子,我们问从 号点到 号点的最大距离是多少?很容易看出 号点到 号有两条路径,通过观察,我们易得,只要到终点的其中两条路径不相等,则这个子图是正环,也就是子图内的所有点的到图内任意点的距离都是可以无限刷分的。

- 直接暴力搜图的肯定是不行的,所以我想到的一个类似前缀和的方法。还是那个图,如果我们问 号点到 号点的最长路,我们就可以用 到 号点的最长路减 到 号点的最长路,即 其中 为 到 点的最长路。
按上述枚举一遍边,最后输出答案。
代码
CPP#include<bits/stdc++.h>
using namespace std;
// 表示从一个节点到另一个节点的有向边
struct node
{
long long to, z; // to: 目标节点, z: 边的权值
};
vector<node> v[1000009];
long long n, m, q, x, y, t;
long long l[1000009]; // l[]: 节点 i 在当前子图中的基准得分
long long j[1000009]; // j[]: 节点 i 所属的子图编号
long long cnt; // cnt: 当前子图的编号
long long p[1000009]; // p[]: 标记子图 i 是否存在正环(可获得无限分数)
bool f[1000009];
void dfs(long long dis)
{
j[dis] = cnt;
f[dis] = true;
long long len = v[dis].size();
for(long long i = 0; i < len; i++) // 遍历所有边
{
long long u = v[dis][i].to;
if(f[u] == false) // 如果目标节点未被访问
{
l[u] = l[dis] + v[dis][i].z;
dfs(u);
}
else if(l[u] != l[dis] + v[dis][i].z) // 说明存在正环
p[cnt] = 1; // 标记当前子图存在正环
}
return ;
}
int main()
{
scanf("%lld%lld%lld", &n, &m, &q);
for(long long i = 1; i <= m; i++)
{
scanf("%lld%lld%lld", &x, &y, &t);
node p;
p.to = y, p.z = t; // 设置正向边(x->y,得分为 t)
v[x].push_back(p);
p.to = x, p.z = -t; // 设置反向边(y->x,得分为 -t)
v[y].push_back(p);
}
for(long long i = 1; i <= n; i++) // 遍历所有节点,处理各个子图
if(f[i] == false) // 如果节点 i 未被访问(属于新的子图)
{
cnt++; // 子图编号加 1
dfs(i); // 从节点 i 开始深度优先搜索
}
while(q--)
{
scanf("%lld%lld", &x, &y);
if(j[x] != j[y]) // 如果两个节点不在同一个子图中
printf("nan\n");
else if(p[j[x]]) // 存在正环
printf("inf\n");
else printf("%lld\n", l[y] - l[x]);
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...