acwing算法提高之图论--有向图的强连通分量

embedded/2024/10/19 2:20:06/

目录

  • 1 介绍
  • 2 训练

1 介绍

本博客介绍有向图的强连通分量的题目。

连通分量:是针对有向图的一个概念。对于分量中任意两个结点a、b,必然可以从a走到b,且从b走到a。
强连通分量:是针对有向图的一个概念。极大强连通分量,也就是说再加一个结点,它就不是连通分量。

强连通分量,用来将一个有向图转化为一个有向无环图(DAG、拓扑图)。方法是缩点,将所有连通分量缩成一个点。
有向无环图有很多好处,可以递推(即拓扑序)求最短路或最长路。

求解方法Tarjan算法

2 训练

题目1:1174受欢迎的牛

C++代码如下,

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 10010, M = 50010;int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt, Size[N];
int dout[N];void add(int a, int b) {e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}void tarjan(int u) {dfn[u] = low[u] = ++ timestamp;stk[++top] = u, in_stk[u] = true;for (int i = h[u]; i != -1; i = ne[i]) {int j = e[i];if (!dfn[j]) {tarjan(j);low[u] = min(low[u], low[j]);} else if (in_stk[j]) {low[u] = min(low[u], dfn[j]);}}if (dfn[u] == low[u]) {++scc_cnt;int y;do {y = stk[top--];in_stk[y] = false;id[y] = scc_cnt;Size[scc_cnt] ++;} while (y != u);}
}int main() {scanf("%d%d", &n, &m);memset(h, -1, sizeof h);while (m--) {int a, b;scanf("%d%d", &a, &b);add(a, b);}for (int i = 1; i <= n; ++i) {if (!dfn[i]) {tarjan(i);}}for (int i = 1; i <= n; ++i) {for (int j = h[i]; ~j; j = ne[j]) {int k = e[j];int a = id[i], b = id[k];if (a != b) dout[a]++;}}int zeros = 0, sum = 0;for (int i = 1; i <= scc_cnt; ++i) {if (!dout[i]) {zeros++;sum += Size[i];if (zeros > 1) {sum = 0;break;}}}printf("%d\n", sum);return 0;
}

题目2:367学校网络

C++代码如下,

#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 110, M = 10010;int n;
int h[N], e[M], ne[M], idx;
int dfn[M], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt;
int din[N], dout[N];void add(int a, int b) {e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}void tarjan(int u) {dfn[u] = low[u] = ++ timestamp;stk[++top] = u, in_stk[u] = true;for (int i = h[u]; ~i; i = ne[i]) {int j = e[i];if (!dfn[j]) {tarjan(j);low[u] = min(low[u], low[j]);} else if (in_stk[j]) {low[u] = min(low[u], dfn[j]);}}if (dfn[u] == low[u]) {++scc_cnt;int y;do {y = stk[top--];in_stk[y] = false;id[y] = scc_cnt;}  while (y != u);}
}int main() {cin >> n;memset(h, -1, sizeof h);for (int i = 1; i <= n; ++i) {int t;while (cin >> t, t) add(i, t);}for (int i = 1; i <= n; ++i) {if (!dfn[i]) {tarjan(i);}}for (int i = 1; i <= n; ++i) {for (int j = h[i]; j != -1; j = ne[j]) {int k = e[j];int a = id[i], b = id[k];if (a != b) {dout[a]++;din[b]++;}}}int a = 0, b = 0;for (int i = 1; i <= scc_cnt; ++i) {if (!din[i]) a++;if (!dout[i]) b++;}printf("%d\n", a);if (scc_cnt == 1) puts("0");else printf("%d\n", max(a, b));return 0;
}

题目3:1175最大半连通子图

C++代码如下,

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_set>using namespace std;typedef long long LL;const int N = 100010, M = 2000010;
int n, m, mod;
int h[N], hs[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt, scc_size[N];
int f[N], g[N];void add(int h[], int a, int b) {e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}void tarjan(int u) {dfn[u] = low[u] = ++ timestamp;stk[++top] = u, in_stk[u] = true;for (int i = h[u]; ~i; i = ne[i]) {int j = e[i];if (!dfn[j]) {tarjan(j);low[u] = min(low[u], low[j]);} else if (in_stk[j]) {low[u] = min(low[u], dfn[j]);} }if (dfn[u] == low[u]) {++scc_cnt;int y;do {y = stk[top--];in_stk[y] = false;id[y] = scc_cnt;scc_size[scc_cnt]++;} while (y != u);}
}int main() {memset(h, -1, sizeof h);memset(hs, -1, sizeof hs);scanf("%d%d%d", &n, &m, &mod);while (m--) {int a, b;scanf("%d%d", &a, &b);add(h, a, b);}for (int i = 1; i <= n; ++i) {if (!dfn[i]) {tarjan(i);}}unordered_set<LL> S;for (int i = 1; i <= n; ++i) {for (int j = h[i]; ~j; j = ne[j]) {int k = e[j];int a = id[i], b = id[k];LL hash = a * 1000000ll + b;if (a != b && !S.count(hash)) {add(hs, a, b);S.insert(hash);}}}for (int i = scc_cnt; i; i--) {if (!f[i]) {f[i] = scc_size[i];g[i] = 1;}for (int j = hs[i]; ~j; j = ne[j]) {int k = e[j];if (f[k] < f[i] + scc_size[k]) {f[k] = f[i] + scc_size[k];g[k] = g[i];} else if (f[k] == f[i] + scc_size[k]) {g[k] = (g[k] + g[i]) % mod;}}}int maxf = 0, sum = 0;for (int i = 1; i <= scc_cnt; ++i) {if (f[i] > maxf) {maxf = f[i];sum = g[i];} else if (f[i] == maxf) sum = (sum + g[i]) % mod;}printf("%d\n", maxf);printf("%d\n", sum);return 0;
}

题目4:368银河

C++代码如下,

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;typedef long long LL;const int N = 100010, M = 600010;
int n, m;
int h[N], hs[N], e[M], ne[M], w[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt, sz[N];
int dist[N];void add(int h[], int a, int b, int c) {e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}void tarjan(int u) {dfn[u] = low[u] = ++ timestamp;stk[++top] = u, in_stk[u] = true;for (int i = h[u]; ~i; i = ne[i]) {int j = e[i];if (!dfn[j]) {tarjan(j);low[u] = min(low[u], low[j]);} else if (in_stk[j]) low[u] = min(low[u], dfn[j]);}if (dfn[u] == low[u]) {++scc_cnt;int y;do {y = stk[top--];in_stk[y] = false;id[y] = scc_cnt;sz[scc_cnt] ++;} while (y != u);}
}int main() {scanf("%d%d", &n, &m);memset(h, -1, sizeof h);memset(hs, -1, sizeof hs);for (int i = 1; i <= n; ++i) add(h, 0, i, 1);while (m--) {int t, a, b;scanf("%d%d%d", &t, &a, &b);if (t == 1) add(h, b, a, 0), add(h, a, b, 0);else if (t == 2) add(h, a, b, 1);else if (t == 3) add(h, b, a, 0);else if (t == 4) add(h, b, a, 1);else add(h, a, b, 0);}tarjan(0);bool success = true;for (int i = 0; i <= n; ++i) {for (int j = h[i]; ~j; j = ne[j]) {int k = e[j];int a = id[i], b = id[k];if (a == b) {if (w[j] > 0) {success = false;break;}} else {add(hs, a, b, w[j]);}}if (!success) break;}if (!success) puts("-1");else {for (int i = scc_cnt; i; --i) {for (int j = hs[i]; ~j; j = ne[j]) {int k = e[j];dist[k] = max(dist[k], dist[i] + w[j]);}}LL res = 0;for (int i = 1; i <= scc_cnt; ++i) {res += (LL)dist[i] * sz[i];}printf("%lld\n", res);}return 0;
}

http://www.ppmy.cn/embedded/10045.html

相关文章

day_8题解

利用最大公约数求最小公倍数 #include<iostream> using namespace std;int gcd(int a,int b) {return b?gcd(b,a%b):a; }int main() {long long a,b;cin>>a>>b;long long ansgcd(a,b);cout<<(a*b)/ans<<endl;return 0; }排序遍历&#xff0c;记…

【MATLAB源码-第36期】matlab基于BD,SVD,ZF,MMSE,MF,SLNR预编码的MIMO系统误码率分析。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. MIMO (多输入多输出)&#xff1a;这是一个无线通信系统中使用的技术&#xff0c;其中有多个发送和接收天线。通过同时发送和接收多个数据流&#xff0c;MIMO可以增加数据速率和系统容量&#xff0c;同时提高信号的可靠性。…

qt之QSS常见属性

本文通过以下方式来设置QSS 控件名->setStyleSheet(""); 设置字体大小 font-size:18pt; 设置背景颜色 background-color:red; 或 background-color:#111111; 或 background-color:rgba(229,229,229,0); 注&#xff1a;rgba的最后一个值代表透明度 设置…

【汇编】指令系统的寻址方式

指令系统的寻址方式 指令系统的寻址方式是指计算机处理器在执行指令时&#xff0c;如何定位并访问指令中操作数所在的内存地址或寄存器&#xff08;寻址方式&#xff1a;获取操作数所在地址的方法&#xff09; 指令中的操作数 通常一条指令包含操作符和操作数&#xff0c;操…

哈希表详解

目录 1.unordered系列关联式容器 2.哈希 3.unordered_map和unordered_set哈希实现 4.代码总和 1.unordered系列关联式容器 1.1unordered系列 c98的STL里面提供了底层为红黑树的关联式容器(set和map); 但是在结点数目很多的时候查询的效率就低了, 所以c11里STL又提供了四个…

机器学习之增强学习DQN(Deep Q Network)

增强学习(Reinforcement Learning, RL)中的Deep Q Network (DQN)是一种用于学习动作选择的深度学习模型。它是基于Q-learning算法的一种扩展,通过使用深度神经网络来估计Q值函数,从而实现对复杂环境中动作的学习和决策。 下面是一般情况下实现DQN的一些步骤: 定义状态空间和…

ChatGPT在线网页版(与GPT Plus会员完全一致)

ChatGPT镜像 今天在知乎看到一个问题&#xff1a;“平民不参与内测的话没有账号还有机会使用ChatGPT吗&#xff1f;” 从去年GPT大火到现在&#xff0c;关于GPT的消息铺天盖地&#xff0c;真要有心想要去用&#xff0c;途径很多&#xff0c;别的不说&#xff0c;国内GPT的镜像…

物联网通信中NB-IoT、Cat.1、Cat.M该如何选择?

物联网通信中NB-IoT、Cat.1、Cat.M该如何选择? 参考链接:物联网通信中NB-IoT、Cat.1、Cat.M该如何选择?​​ 在我们准备设计用于大规模联网的物联网设备时,选择到适合的LTE IoT标准将是我们遇到的难点。这是我们一开始设计产品方案就需要解决的一个问题,其决定我们设备需…