kuangbin
专题链接:https://vjudge.net/article/752
kuangbin
专题十二 基础DP1 题解+总结:https://www.cnblogs.com/RioTian/p/13110438.html
kuangbin
专题六 最小生成树 题解+总结:https://www.cnblogs.com/RioTian/p/13380764.html
先挖个坑,这几天抓紧填
总结
目录:
目录
- 总结
- 1.Network of Schools /强连通分量+缩点
- 2.Network /割点模板题
- 3.Critical Links /桥的模板题
- 4.Network /桥+LCA
- 5.Redundant Paths /双连通分量
- 6.Strongly connected /强通块+缩点
- 7.Caocao’s Bridges /桥
- 8.Warm up /图论综合好题
- 9.Prince and Princess /完美匹配+SCC
1.Network of Schools /强连通分量+缩点
原题链接:传送门
思路:
tarjan求强连通分量,然后缩点,查看有几个强连通图,查看缩点后的DAG入度为0和出度为0的多少,选取其中最大值。
新的一条线为入度为0的连到出度为0,所以取max 。
#include
#include
#include
#include
#include
using namespace std;
#define ms(a,b) memset(a,b,sizeof a)
typedef long long ll;
const int maxn = 5e5 + 5;
ll head[maxn],dfn[maxn], low[maxn];
bool book[maxn];// dfn 时间戳 low回溯 book 是否在栈中
ll ans[maxn]; // ans为强连通分量里面的点数
ll out[maxn], in[maxn]; // out 出度 in 入度
ll col[maxn], s[maxn];// s栈 col强连通
ll k, ti, top, cnt, n, m;
struct node {
ll v, next;
}e[maxn << 1];
void add(ll u, ll v) {
e[++k].v = v; e[k].next = head[u];
head[u] = k;
}
void tarjan(ll x) {
dfn[x] = low[x] = ++ti, book[x] = 1, s[++top] = x;
for (int i = head[x]; i; i = e[i].next) {
ll u = e[i].v;
if (!dfn[u]) tarjan(u), low[x] = min(low[x], low[u]);
else if (book[u]) low[x] = min(low[x], dfn[u]);
}
if (low[x] == dfn[x]) {
++cnt; ll y;
do {
y = s[top--], book[y] = 0;
col[y] = cnt;
ans[cnt]++;
} while (x != y);
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
ll v; while (cin >> v && v)add(i, v);
}
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) tarjan(i);
}
for(int i = 1;i<=n;++i)
for(int j=head[i];j;j = e[j].next)
if (col[e[j].v] != col[i])
++out[col[i]], ++in[col[e[j].v]];
ll res1 = 0, res2 = 0;
for (int i = 1; i <= cnt; i++) {
if (!out[i]) res1++;
if (!in[i]) res2++;
}
if (cnt == 1) cout << 1 << endl << 0 << endl;
else cout << res2 << endl << max(res1, res2) << endl;
}
Kosaraju 算法
#include
#include
#include
#include
#include
using namespace std;
#define MAX_V 100 + 10
#define ms(a,b) memset(a,b,sizeof a)
int V; // 顶点数
vector G[MAX_V]; // 图的邻接表表示
vector rG[MAX_V]; // 反向图
vector vs; // 后序遍历顺序的顶点列表
bool book[MAX_V]; // 访问标记
int cmp[MAX_V]; // 所属强连通分量的拓补序
int in[MAX_V], out[MAX_V]; // 入度、出度
void add_Edge(int from, int to) {
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(const int &v) {
book[v] = true;
for (int i = 0; i < G[v].size(); ++i) {
if (!book[G[v][i]])
dfs(G[v][i]);
}
vs.push_back(v);
}
void rdfs(const int& v, const int& k) {
book[v] = true;
cmp[v] = k;
for (int i = 0; i < rG[v].size(); ++i) {
if (!book[rG[v][i]])
rdfs(rG[v][i], k);
}
}
int scc() {
ms(book, false); vs.clear();
for (int v = 0; v < V; ++v) {
if (!book[v])
dfs(v);
}
ms(book, false);
int k = 0;
for (int i = vs.size() - 1; i >= 0; --i) {
if (!book[vs[i]])
rdfs(vs[i], k++);
}
return k;
}
int main() {
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//尝试过快读,莫名比scanf和关闭流同步还速度慢
cin >> V;
for (int u = 0, v; u < V; ++u) {
while (cin>>v && v)
add_Edge(u, --v);
}
int n = scc();
// 特殊情况
if (n == 1)return cout << 1 << endl << 0, 0;
for (int u = 0; u < V; ++u)
for (int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if (cmp[u] != cmp[v]) // 强连通分量算一个点
++out[cmp[u]], ++in[cmp[v]];
}
int zero_in = 0, zero_out = 0;
for (int i = 0; i < n; ++i){
if (in[i] == 0) ++zero_in;
if (out[i] == 0)++zero_out;
}
cout << zero_in << endl << max(zero_in, zero_out) << endl;
}
2.Network /割点模板题
原题链接:传送门
思路:
3.Critical Links /桥的模板题
原题链接:传送门
思路:
4.Network /桥+LCA
原题链接:传送门
思路:
5.Redundant Paths /双连通分量
原题链接:传送门
思路:
6.Strongly connected /强通块+缩点
原题链接:传送门
思路:
7.Caocao’s Bridges /桥
原题链接:传送门
思路:
8.Warm up /图论综合好题
原题链接:传送门
思路:
9.Prince and Princess /完美匹配+SCC
原题链接: 传送门
思路: