C++,给定一张n个点m条边的有向图,统计有多少点满足:从图上任意点出发,都可以沿图上的有向边到达这个点
时间: 2023-02-25 10:11:33 浏览: 222
称这样的点为"强连通点",要统计这样的点的个数,就需要使用图的强连通分量的概念。强连通分量指的是一个点集,其中任意两点都是强连通的,也就是说可以从任意一个点出发到达其他任意点。强连通分量的点的个数就是答案。
C 语言中,可以使用 tarjan 算法或者 kosaraju 算法来求解图的强连通分量。具体实现细节可以参考一些数据结构与算法的学习资料。
相关问题
我们称简单有向图 � , � G,H 本质相同,当且仅当: 对于任意点对 ( � , � ) (u,v),若在图 � G 中从 � u 出发能走到 � v,则在图 � H 中从 � u 出发能走到 � v。反之若在图 � H 中从 � u 出发能走到 � v,则在图 � G 中从 � u 出发也能走到 � v。 若对于简单有向图 � G,不存在其他简单有向图 � H 与其本质相同,则我们称图 � G 为 单图。 � T 次询问,每次询问给定一个正整数 � n,请你回答 � n 个点的有标号单图数。c++代码
以下是使用动态规划算法求解的 C++ 代码:
```cpp
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 20;
const int MAXS = 1 << MAXN;
const int MOD = 998244353;
int n;
int g[MAXN][MAXN];
int dp[MAXS];
bool vis[MAXS];
int dfs(int s) {
if (vis[s]) {
return dp[s];
}
vis[s] = true;
if (s == (1 << n) - 1) {
dp[s] = 1;
return dp[s];
}
int u;
for (u = 0; u < n; u++) {
if ((s & (1 << u)) == 0) {
break;
}
}
int &ans = dp[s];
for (int v = u + 1; v < n; v++) {
if ((s & (1 << v)) == 0 && g[u][v]) {
ans = (ans + dfs(s | (1 << u) | (1 << v))) % MOD;
}
}
return ans;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> g[i][j];
}
}
memset(vis, false, sizeof(vis));
cout << dfs(0) << endl;
return 0;
}
```
其中,`g[i][j]` 表示从顶点 `i` 到顶点 `j` 是否存在一条有向边。`dp[s]` 表示状态为 `s` 的有标号单图数。`vis[s]` 表示状态 `s` 是否已经被访问过。在 `dfs` 函数中,通过枚举两个未被访问的顶点 `u` 和 `v`,如果从 `u` 到 `v` 存在一条有向边,则递归计算状态 `s | (1 << u) | (1 << v)` 的有标号单图数,并累加到答案中。最后返回状态为 0 的有标号单图数即可。
首页 题库 比赛 作业 讨论 评测记录 默认 hekangbao2027 【模板】单源最短路径(标准版) 题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。 然后呢? 100 → 60 100→60; Ag → Cu Ag→Cu; 最终,他因此没能与理想的大学达成契约。 小 F 衷心祝愿大家不再重蹈覆辙。 题目描述 给定一个 n n 个点, m m 条有向边的带非负权图,请你计算从 s s 出发,到每个点的距离。 数据保证你能从 s s 出发到任意点。 输入格式 第一行为三个正整数 n , m , s n,m,s。 第二行起 m m 行,每行三个非负整数 u i , v i , w i u i ,v i ,w i ,表示从 u i u i 到 v i v i 有一条权值为 w i w i 的有向边。 输出格式 输出一行 n n 个空格分隔的非负整数,表示 s s 到每个点的距离。 输入数据 1 4 6 1 1 2 2 2 3 2 2 4 1 1 3 5 3 4 3 1 4 4 输出数据 1 0 2 4 3 提示 样例解释请参考 数据随机的模板题。 1 ≤ n ≤ 1 0 5 1≤n≤10 5 ; 1 ≤ m ≤ 2 × 1 0 5 1≤m≤2×10 5 ; s = 1 s=1; 1 ≤ u i , v i ≤ n 1≤u i ,v i ≤n; 0 ≤ w i ≤ 1 0 9 0≤w i ≤10 9 , 0 ≤ ∑ w i ≤ 1 0 9 0≤∑w i ≤10 9 。 本题数据可能会持续更新,但不会重测,望周知。 2018.09.04 数据更新 from @zzq C++14
您提到的内容涉及的是一个典型的 **单源最短路径** 问题,并附有一个具体的题目背景以及相关的输入输出格式说明。以下是对此内容的具体解析:
---
### 单源最短路径 (SSSP) 概述
#### 定义
单源最短路径问题是图论中的经典问题之一,目标是从某个起点出发,找到到达所有其他节点的最短距离。如果图中边权重均为非负,则可以使用经典的 Dijkstra 算法解决该问题。
#### 输入分析
根据您的描述:
- 图中有 `n` 个顶点和 `m` 条有向边;
- 边 `(ui, vi)` 的权重为 `wi`;
- 起始点固定为 `s = 1`;
我们需要通过某种算法(如Dijkstra 或 SPFA),计算出从起始点到每一个点的距离。
---
### 示例解释 - 样例数据分析
对于样例数据:
```
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
```
我们可以构建如下加权有向图:
- 节点编号:1、2、3、4;
- 边及权重信息如下表所示:
| u | v | w |
|---|---|---|
| 1 | 2 | 2 |
| 2 | 3 | 2 |
| 2 | 4 | 1 |
| 1 | 3 | 5 |
| 3 | 4 | 3 |
| 1 | 4 | 4 |
运行 Dijkstra 后的结果是 `[0, 2, 4, 3]`,即分别为从起点 1 到各节点的最小代价。
---
### 解决方案步骤
我们可以通过优先队列优化版本的 **Dijkstra 算法** 实现此功能,其时间复杂度大约为 \(O(m \log n)\),适用于大规模稀疏图。下面是基于 C++ 的伪代码实现框架:
```cpp
#include <bits/stdc++.h>
using namespace std;
const long long INF = LLONG_MAX; // 设置无穷大
int main() {
int n, m, s;
cin >> n >> m >> s;
vector<vector<pair<int, int>>> graph(n + 1); // 构建邻接表存储图
for(int i = 0;i<m;i++) { // 初始化边
int ui, vi, wi;
cin>>ui>>vi>>wi;
graph[ui].emplace_back(vi, wi);
}
priority_queue<pair<long long,int>,vector<pair<long long,int>>,greater<>> pq;
// 小根堆用于选取当前最优路径
vector<long long> dist(n+1,INF);
dist[s]=0; pq.emplace(0LL,s);
while(!pq.empty()) {
auto [curDist,node] = pq.top(); pq.pop();
if(curDist >dist[node]) continue;// 剪枝
for(auto &[nextNode,nextCost]:graph[node]){
if(dist[nextNode]>dist[node]+ nextCost){
dist[nextNode] = dist[node] + nextCost;
pq.emplace(dist[nextNode],nextNode);
}
}
}
for(int node=1;node<=n;node++) cout<<dist[node]<<" "; // 输出结果至文件或屏幕
}
```
上述程序实现了以下关键操作:
1. 使用了优先队列加速访问最近未处理结点的操作。
2. 动态更新每个点的最佳可达成本并加入待探索集合。
---
###
阅读全文
相关推荐














