图结构模板

大量图结构模板,可能会有帮助

#include<bits/stdc++.h>
#define MAXN 100000
#define D 10
#define MAXM 10000010
using std::cin;
using std::cout;
using std::endl;
int m, n;//m为边数,n为点数
//图的存储

//邻接矩阵
int a[5010][5010];
void init() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
a[x][y] = 1;
}
}

//边表
struct node {
int x, y;
} edge[MAXM + D];

void init() {
cin >> n >> m;
for (int i = 1; i <= m; ++i)
cin >> edge[i].x >> edge[i].y;
}

//前向星
struct node {
int x, y;
} edge[500010];

int st[MAXN + D], en[MAXN + D];

inline bool cmp(node x, node y) {
return x.x < y.y;
}

void init() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) cin >> edge[i].x >> edge[i].y;
std::sort(edge + 1, edge + 1 + m, cmp);
st[edge[1].x] = 1;
for (int i = 2; i <= m; ++i) {
if (edge[i].x != edge[i - 1].x) en[edge[i - 1].x] = i - 1;
st[edge[i].x] = i;
}
en[edge[m].x] = m;
}

//链表/链式前向星
int lin[MAXN + D], len = 0;
struct node {
int y, ne;
} edge[MAXM + D];

inline void addedge(int x, int y) {
edge[++len].y = y;
edge[len].ne = lin[x];
lin[x] = len;
}

void init() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int x, y;
cin >> x >> y;
addedge(x, y);
}
}

//图的遍历
//DFS
void dfs(int x) {
vis[x] = true;
for (int i = lin[x], y; i; i = edge[i].ne) if (!vis[y = edge[i].y]) dfs(y);
}

//DFS(邻接矩阵)
void dfs(int x) {
vis[x] = true;
for (int i = 1; i <= n; ++i) if (a[x][i] && !vis[i]) dfs(i);
}

//BFS
int head, tail, queue[MAXN + D];
void bfs(int s) {
vis[s] = true;
head = 0, tail = 1;
queue[1] = s;
while (head++ < tail) {
int x = queue[head];
for (int i = lin[x], y; i; i = edge[i].ne) if (!vis[y = edge[i].y]) {
queue[++tail] = y;
vis[y] = true;
}
}
}

//BFS(邻接矩阵)
int head, tail, queue[MAXN + D];
void bfs(int s) {
vis[s] = true;
head = 0, tail = 1;
queue[1] = s;
while (head++ < tail) {
int x = queue[head];
for (int i = 1; i <= n; ++i) if (a[x][i] && !vis[i]) {
queue[++tail] = i;
vis[i] = true;
}
}
}

//最短路
//Floyd
void Floyd() {
for (int k = 1; k <= n; ++k) for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) a[i][j] = std::min(a[i][j], a[i][k] + a[k][j]);
}

//Dijkstra
#define INF 0x3f3f3f3f
int dis[10010];
int vis[10010];
void Dijkstra(int s) {
memset(vis, false, sizeof(vis));
for (int i = 1; i <= n; i++) dis[i] = a[s][i];
vis[s] = true;
for (int i = 1; i < n; ++i) {
int min = INF, x = 0;
for (int i = 1; i <= n; ++i)
if (!vis[i] && dis[i] < min) {
min = dis[i];
x = i;
}
if (!x) return;
vis[x] = true;
for (int i = 1; i <= n; ++i) dis[i] = std::min(dis[i], dis[x] + a[x][i]);
}
}

//Dijkstra_with_priority_queue
using std::pair;
using std::priority_queue;
using std::vector;
using std::greater;
using std::make_pair;
#define INF 0x3f3f3f3f
typedef pair<int, int> pii;
pirority_queue<pii, vector<pii>, greater<pii> > queue;
void Dijkstra(int s) {
memset(dis, 0x3f, sizeof(dis));
memset(vis, false, sizeof(vis));
dis[s] = 0;
queue.push(make_pair(dis[s], 0));
while (!q.empty()) {
pii tmp = q.top();
q.pop();
int x = tmp.second;
if (vis[x]) continue;
vis[x] = true;
for (int i = lin[x], y; i; i = edge[i].ne) if (dis[y = edge[i].y] > dis[x] + edge[i].v) {
dis[y] = dis[x] + edge[i].v;
if (!vis[y]) q.push(make_pair(dis[y], y));
}
}
}

//Bellman-Ford
void Bellman_Ford(int s) {
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
bool rel;
for (int i = 1; i <= n; ++i) {
rel = false;
for (int j = 1; j <= len; ++j) if (dis[edge[j].y] > dis[edge[j].x] + edge[j].v)
}
}

//SPFA
int queue[10000010], head, tail;
void SPFA(int s) {
head = 0, tail = 1;
memset(vis, false, sizeof(vis));
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
vis[s] = true;
queue[1] = s;
while (head++ < tail) {
int x = queue[head];
vis[x] = false;
for (int i = lin[x], y; i; i = edge[i].ne) if (dis[y = edge[i].y] > dis[x] + edge[i].v) {
dis[y] = dis[x] + edge[i].v;
if (!vis[y]) {
vis[y] = true;
queue[++tail] = y;
}
}
}
}

//最小生成树
//Prim
#define INF 0x3f3f3f3f
int Prim() {
memset(vis, false, sizeof(vis));
vis[1] = true;
int sum = 0;
for (int i = 1; i <= n; ++i) dis[i] = a[1][i];
for (int i = 1; i < n; ++i) {
int min = INF, x = 0;
for (int j = 1; j <= n; ++j) if (!vis[j] && dis[j] < min) {
min = dis[j];
x = j;
}
vis[x] = true;
sum += min;
for (int j = 1; j <= n; ++j) dis[j] = std::min(dis[j], a[x][j]);
}
return sum;
}

//Kruskal
struct node {
int x, y, v;
} edge[100010];

inline bool cmp(node x, node y) {
return x.v <y.v;
}

int father[MAXN + D];

int getfather(int x) {
return (father[x] == x) ? x : (father[x] = getfather(father[x]));
}

int Kruskal() {
for (int i = 1; i <= n; ++i) father[i] = i;
int sum = 0, cnt = 0;
std::sort(edge + 1, edge + 1 + m, cmp);
for (int i = 1; i <= m && cnt < n - 1; ++i) {
int x = getfather(edge[i].x), y = getfather(edge[i].y);
if (x != y) {
++cnt;
sum += edge[i].v;
father[x] = y;
}
}
return sum;
}

//拓扑排序
int queue[MAXN + D], head, tail, in_degree[MAXN + D], ans[100][MAXN + D], tot = 0;

void init() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int x, y;
cin >> x >> y;
addedge(x, y);
++in_degree[y];
}
}

//BFS
void bfs() {
head = 0, tail = 0;
for (int i = 1; i <= n; ++i) if (!in_degree[i]) queue[++tail] = y;
while (head++ < tail) {
int x = queue[head];
for (int i = lin[x],y; i; i = edge[i].ne) if (!(--in_degree[y = edge[i].y])) queue[++tail] = y;
}
}

//DFS
void dfs(int x, int dep) {
queue[dep] = x;
vis[x] = true;
if (dep == n) {
++tot;
for (int i = 1; i <= n; ++i) ans[tot][i] = queue[i];
vis[x] = false;
}
for (int i = lin[x]; i; i = edge[i].ne) --in_degree[edge[i].y];
for (int i = 1; i <= n; ++i) if (!vis[i] && !in_degree[i]) dfs(i, dep + 1);
for (int i = lin[x]; i; i = edge[i].ne) ++in_degree[edge[i].y];
vis[x] = false;
}

//Tarjan
//割点
int dfn[MAXN + D], low[MAXN + D], _clock = 0;
bool iscut[MAXN + D]
void tarjan(int x, int par = 0) {
int child = 0;
dfn[x] = low[x] = ++_clock;
for (int i = lin[x], y; i; i = edge[i].ne) {
if ((y = edge[i].y) == par) continue;
if (!dfn[y]) {
tarjan(y, x);
if (low[y] < low[x]) low[x] = low[y];
else if (low[y] >= dfn[x]) ++child;
} else if (dfn[y] < low[x]) low[x] = dfn[y];
}
if (child >= 2 || (child == 1 && par)) iscut[x] = true;
}

int main() {
for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//点双连通分量
using std::vector;
vector<int> bcc[MAXN + D];
int size[MAXN + D], dfn[MAXN + D], low[MAXN + D], _clock = 0, bel[MAXN + D], stack[MAXM + D], top = 0;
void tarjan(int x, int par = 0) {
int child = 0;
dfn[x] = low[x] = ++_clock;
for (int i = lin[x], y; i; i = edge[i].ne) {
if ((y = edge[i].y) == par) continue;
if (!dfn[y]) {
stack[++top] = i;
tarjan(y, x);
if (low[y] < low[x]) low[x] = low[y];
else if (low[y] >= dfn[x]) {
++child;
int k;
++tot;
do {
k = stack[top--];
if (bel[edge[k].x] != tot) {
bel[edge[k].x] = tot;
bcc[tot].push_back(edge[k].x);
++size[tot];
}
if (bel[edge[k].y] != tot) {
bel[edge[k].y] = tot;
bcc[tot].push_back(edge[k].y);
++size[tot];
}
} while (k != i);
}
} else if (dfn[y] < low[x]) {
low[x] = dfn[y];
stack[++top] = i;
}
}
if (child >= 2 || (par && child)) iscut[x] = true;
}

int main() {
for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//割边
int dfn[MAXN + D], low[MAXN + D], _clock = 0, rev[(MAXM << 1) + D];
bool isbridge[(MAXM << 1) + d];
void tarjan(int x, int par = 0) {
dfn[x] = low[x] = ++_clock;
for (int i = lin[x], y; i; i = edge[i].ne) {
if (i == par) continue;
if (!dfn[y = edge[i].y]) {
tarjan(y, rev[i]);
if (low[y] < low[x]) low[x] = low[y];
} else if (dfn[y] < low[x]) low[x] = dfn[y];
}
if (dfn[x] == low[x]) isbridge[par] = isbridge[rev[par]] = true;
}

int main() {
for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//求割边后求边双连通分量
int tot = 0, bel[MAXN + D], size[MAXN + D];
void dfs(int i) {
bel[i] = tot;
++size[tot];
for (int i = lin[x], y; i; i = edge[i].ne) {
if (isbridge[i] || bel[y = edge[i].y]) continue;
dfs(y);
}
}

int main() {
for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
for (int i = 1; i <= n; ++i) if (!bel[i]) {
++tot;
dfs(i);
}
}

/连通分量
int dfn[MAXN + D], low[MAXN + D], _clock = 0, top = 0, stack[MAXN + D], bel[MAXN + D], size[MAXN + D], tot;
bool vis[MAXN + D];
void tarjan(int x) {
vis[x] = true;
stack[++top] = x;
dfn[x] = low[x] = ++_clock;
for (int i = lin[x], y; i; i = edge[i].ne) {
if (!dfn[y = edge[i].y]) {
tarjan(y);
if (low[y] < low[x]) low[x] = low[y];
} else if (vis[y] && dfn[y] < low[x]) low[x] = dfn[y];
}
if (dfn[x] == low[x]) {
int k;
tot++;
do {
k = stack[top--];
vis[k] = false;
++size[tot];
bel[k] = tot;
} while (k != x);
}
}

int main() {
for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//DFS序列化
int st[MAXN + D], en[MAXN + D], _clock = 0;
void dfs(int x, int par = 0) {
st[x] = ++_clock;
for (int i = lin[x], y; i; i = edge[i].ne) if ((y = edge[i].y) != par) dfs(y, x);
en[x] = _clock;
}

//轻重链剖分
int st[MAXN + D], en[MAXN + D], _clock = 0, top[MAXN + D], size[MAXN + D], son[MAXN + D], father[MAXN + D], depth[MAXN + D];
void find_heavy_edge(int x, int par = 0) {
father[x] = par;
depth[x] = depth[par] + 1;
size[x] = 1;
int maxsize = 0;
son[x] = 0;
for (int i = lin[x], y; i; i = edge[i].y) {
if ((y = edge[i].y) == par) continue;
find_heavy_edge(y, x);
if (size[y] > maxsize) {
maxsize = size[y];
son[x] = y;
}
size[x] += size[y];
}
}

void connect_heavy_edge(int x, int par) {
st[x] = ++_clock;
top[x] = par;
if (son[x]) connect_heavy_edge(son[x], par);
for (int i = lin[x], y; i; i = edge[i].ne) {
y = edge[i].y;
if (y == par || y == son[x]) continue;
connect_heavy_edge(y, y);
}
en[x] = _clock;
}

int main() {
find_heavy_edge(1);
connect_heavy_edge(1, 1);
}

//LCA
//树链剖分
int LCA(int u, int v) {
while (top[u] != top[v]) {
if (depth[top[u]] < depth[top[v]]) std::swap(u, v);
u = father[top[u]];
}
if (depth[u] > depth[v]) std::swap(u, v);
return v;
}

//倍增法
int father[MAXN + D][20], depth[MAXN + D], M;
void dfs(int x) {
for (int i = 1; (1 << i) <= n && father[x][i - 1]; ++i) father[x][i] = father[father[x][i - 1]][i - 1];
for (int i = lin[x], y; i; i = edge[i].ne) {
if ((y = edge[i].y) == father[x][0]) continue;
father[y][0] = x;
dfs(y);
}
}

int LCA(int u, int v) {
if (depth[u] < depth[v]) std::swap(u, v);
for (int i = 0; depth[u] != depth[v]; ++i) if ((1 << i) & (depth[u] - depth[v])) u = father[u][i];
if (u == v) return u;
for (int i = M; i >= 0; --i) if (father[u][i] != father[v][i]) {
u = father[u][i];
v = father[v][i];
}
return father[u][0];
}

int main() {
for (M = 0; (1 << M) <= n; ++M);
--M;
dfs(1);
}

//tarjan离线法
struct query {
int y, ne, id;
} query[MAXM + D];

int len_query = 0, lin_query[MAXN + D], father[MAXN + D], ans[MAXM + D];
bool vis[MAXN + D];
inline void addquery(int x, int y, int id) {
query[++len_query].y = y;
query[len_query].ne = lin_query[x];
lin_query[x] = len_query;
query[len_query].id = id;
}

int getfather(int x) {
return (father[x] == x) ? x : (father[x] = getfather(father[x]));
}

void tarjan(int x, int par = 0) {
for (int i = lin[x], y; i; i = edge[i].ne) {
if ((y = edge[i].y) == par) continue;
tarjan(y, x);
father[y] = x;
vis[y] = true;
}
for (int i = lin_query[x], y; i; i = query[i].ne) {
if (!vis[y = query[i].y]) continue;
ans[query[i].id] = getfather(y);
}
}

int main() {
for (int i = 1; i <= n; ++i) father[i] = i;
tarjan(1);
}

//点分治
int size[MAXN + D], root, sum = 0, maxsize[MAXN + D];
bool vis[MAXN + D];
void getroot(int x, int par) {
size[x] = 1;
maxsize[x] = 0;
for (int i = lin[x], y; i; i = edge[i].ne) {
y = edge[i].y;
if (y == par || vis[y]) continue;
getroot(y, x);
maxsize[x] = std::max(maxsize[x], size[y]);
size[x] += size[y];
}
maxsize[x] = std::max(maxsize[x], sum - maxsize[x]);
if (maxsize[x] < maxsize[root]) root = x;
}

void cal(int x, int par) {
//计算当前点贡献
for (int i = lin[x], y; i; i = edge[i].ne) {
y = edge[i].y;
if (vis[y] || y == par) continue;
cal(y, x);
}
}

void add(int x, int par, bool opt) {
if (opt) {
//将当前点加入到计算的点中
} else {
//将当前点从已计算的点集删除
}
for (int i = lin[x], y; i; i = edge[i].ne) {
y = edge[i].y;
if (vis[y] || y == par) continue;
add(y, x, opt);
}
}

void solve(int x) {
getroot(x);
vis[x] = true;
for (int i = lin[x], y; i; i = edge[i].ne) {
y = edge[i].y;
if (vis[y]) continue;
cal(y, x);
add(y, x, true);
}
for (int i = lin[x], y; i; i = edge[i].ne) {
y = edge[i].y;
if (vis[y]) continue;
add(y, x, false);
}
for (int i = lin[x], y; i; i = edge[i].ne) {
y = edge[i].y;
if (vis[y]) continue;
sum = size[y];
root = 0;
getroot(y, x);
solve(root);
}
}

int main() {
root = 0;
maxsize[0] = sum = n;
getsize(1, 0);
solve(root);
}

原文地址:https://www.cnblogs.com/AK-ls/p/10107699.html

时间: 2024-10-12 02:42:11

图结构模板的相关文章

图结构练习——最小生成树

图结构练习--最小生成树 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的.现在我们想知道,最少花多少钱修公路可以将所有的城市连在一起,使在任意一城市出发,可以到达其他任意的城市. 输入 输入包含多组数据,格式如下. 第一行包括两个整数n m,代表城市个数和可以修建的公路个数.(n<=100) 剩下m行每行3个正整数a b c,代表城市a 和城市b之间可以修建

图结构练习——判断给定图是否存在合法拓扑序列

图结构练习——判断给定图是否存在合法拓扑序列 Time Limit: 1000MS Memory limit: 65536K 题目描述 给定一个有向图,判断该有向图是否存在一个合法的拓扑序列. 输入 输入包含多组,每组格式如下. 第一行包含两个整数n,m,分别代表该有向图的顶点数和边数.(n<=10) 后面m行每行两个整数a b,表示从a到b有一条有向边. 输出 若给定有向图存在合法拓扑序列,则输出YES:否则输出NO. 示例输入 1 0 2 2 1 2 2 1 示例输出 YES NO #inc

图结构练习——判断给定图是否存在合法拓扑序列(sdutoj)

#include<stdio.h>#include<string.h>int d[15],map[15][15],vis[15];int main(){    int i,j,k,f,n,m,u,v;    while(~scanf("%d%d",&n,&m))    {        memset(d,0,sizeof(d));        memset(map,0,sizeof(map));        memset(vis,0,size

C# 图结构操作

仿造<<Java常用算法手册>>里面对的算法,使用C#实现了一遍. 理论知识我就不讲解了,在这本书里面已经写的非常完美! 代码如何下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 图结构 { public class GraphMatrix { public static in

图结构练习——BFS——从起始点到目标点的最短步数(邻接表+BFS)

图练习-BFS-从起点到目标点的最短步数 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 在古老的魔兽传说中,有两个军团,一个叫天灾,一个叫近卫.在他们所在的地域,有n个隘口,编号为1..n,某些隘口之间是有通道连接的.其中近卫军团在1号隘口,天灾军团在n号隘口.某一天,天灾军团的领袖巫妖王决定派兵攻打近卫军团,天灾军团的部队如此庞大,甚至可以填江过河.但是巫妖王不想付出不必要的代价,他想知道在不修建任何通道的前提下,部队是否

1.7图结构

数据元素存在3种关系: 1)先行后续,即一个数据元素有一个直接前驱和一个直接后继,这种组织结构叫线性结构: 2)层次关系,每一层上数据元素可能和下一层中的多个数据元素相关,但只和上一层中的一个数据元素相关,这类组织结构叫树结构: 3)数据元素间是"一对多"或者"多对一"的关系,即任意两个数据元素之间都可以存在关系,这类组织结构叫图结构: 图:由顶点的非空有限集合V(由N>0个顶点组成)与边的集合E(顶点之间关系)所构成的,分为有向图和无向图. 图的存储形式:邻

一步一步写算法(之图结构)

原文:一步一步写算法(之图结构) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 图是数据结构里面的重要一章.通过图,我们可以判断两个点之间是不是具有连通性:通过图,我们还可以计算两个点之间的最小距离是多少:通过图,我们还可以根据不同的要求,寻找不同的合适路径.当然,有的时候为了计算的需要,我们还需要从图中抽象出最小生成树,这样在遍历计算的时候就不需要持续判断是不是遇到了循环节点.当然,这所有的一切都是从图的表示开始的. 1)矩阵表示 矩

SDUT 2139 图结构练习——BFS——从起始点到目标点的最短步数(BFS + vector)

图结构练习--BFS--从起始点到目标点的最短步数 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 在古老的魔兽传说中,有两个军团,一个叫天灾,一个叫近卫.在他们所在的地域,有n个隘口,编号为1..n,某些隘口之间是有通道连接的.其中近卫军团在1号隘口,天灾军团在n号隘口.某一天,天灾军团的领袖巫妖王决定派兵攻打近卫军团,天灾军团的部队如此庞大,甚至可以填江过河.但是巫妖王不想付出不必要的代价,他想知道在不修建任何通道的前提下

图结构练习——推断给定图是否存在合法拓扑序列(拓扑排序推断环)

图结构练习--推断给定图是否存在合法拓扑序列 Time Limit: 1000MS Memory limit: 65536K 题目描写叙述 给定一个有向图,推断该有向图是否存在一个合法的拓扑序列. 输入 输入包括多组.每组格式例如以下. 第一行包括两个整数n,m.分别代表该有向图的顶点数和边数.(n<=10) 后面m行每行两个整数a b.表示从a到b有一条有向边. 输出 若给定有向图存在合法拓扑序列,则输出YES.否则输出NO. 演示样例输入 1 0 2 2 1 2 2 1 演示样例输出 YES