码迷,mamicode.com
首页 > 其他好文 > 详细

图结构模板

时间:2018-12-12 13:26:17      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:pair   链式前向星   std   push   query   拓扑排序   最小生成树   生成树   clock   

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

#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);
}

图结构模板

标签:pair   链式前向星   std   push   query   拓扑排序   最小生成树   生成树   clock   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!