border="0" width="330" height="86" src="//music.163.com/outchain/player?type=2&id=514765154&auto=1&height=66">
这里记录一下最近写的关于图的东西,图还是比较难的,这里有些可能不能用,但分开来都是对的
#pragma once
//带权
//此文件不能直接使用
#define MAXV 100
#define INF 0x3fffffff
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <utility>
#include <functional>
#include <algorithm>
struct Node
{
int v, w;
Node(int _v, int _w) :v(_v), w(_w) {}; //构造函数
};
std::vector<Node> Adj[MAXV];
int n;
bool vis[MAXV] = { false };
void DFS(int u, int depth) {
vis[u] = true;
printf("%d", u);
for (int i = 0; i < Adj[u].size(); ++i) {
int v_now = Adj[u][i].v;
if (!vis[v_now])
DFS(v_now, depth + 1);
}
}
void DFSTrave() {
for (int u = 0; u < n; ++u) {
if (!vis[u])
DFS(u, 1);
}
}
bool inq[MAXV] = { false };
void BFS(int u) {
std::queue<int> q;
q.push(u);
inq[u] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < Adj[u].size(); ++i) {
int v_now = Adj[u][i].v;
if (!inq[v_now]) {
q.push(v_now);
inq[v_now] = true;
}
}
}
}
void BFSTrave() {
for (int u = 0; u < n; ++u) {
if (!inq[u]) BFS(u);
}
}
//*********Dijkstra算法*************
//O(v^2+e),可以经最小堆优化
int n; //顶点数,MAXV为最大顶点数
int d[MAXV]; //起点到达各点的最短路径长度
bool vis2[MAXV] = { false }; //是否被访问
int pre[MAXV]; //存放前驱下标
void Dijkstra(int s) {
//初始化最短路径为INF
for (int i = 0; i < MAXV; ++i)
d[i] = INF;
for (int i = 0; i < MAXV; ++i)
pre[i] = i;
d[s] = 0; //起点至自身为0
for (int i = 0; i < n; ++i) {
//寻找最小值
int u = -1, min = INF;
for (int j = 0; j < n; ++j) {
if (!vis[j] && d[j] < min) {
u = j;
min = d[j];
}
}
if (u = -1) return; //找不到这样的点,即访问完毕
vis[u] = true; //标记一下访问
for (int j = 0; j < Adj[u].size(); ++j) {
int now = Adj[u][j].v;
if (!vis[now] && d[u] + Adj[u][j].w < d[now])
pre[now] = u; //更新前驱
d[now] = d[u] + Adj[u][j].w;
}
}
}
//*********Bellman-Ford算法*************
//O(ve)
bool Bellman(int s) {
bool isOk = false;
//初始化最短路径为INF
for (int i = 0; i < MAXV; ++i)
d[i] = INF;
d[s] = 0; //起点至自身为0
for (int i = 0; i < n - 1; ++i) {
for (int u = 0; u < n; ++u) {
for (int j = 0; j < Adj[u].size(); ++j) {
int v = Adj[u][j].v;
int w = Adj[u][j].w;
if (d[u] + w < d[v]) {
d[v] = d[u] + w;
isOk = true;
}
}
}
if (isOk) isOk = false;
else break; //已经没有松弛了
}
for (int u = 0; u < n; ++u) {
for (int j = 0; j < Adj[u].size(); ++j) {
int v = Adj[u][j].v;
int w = Adj[u][j].w;
if (d[u] + w < d[v]) {
return false; //还存在松弛有负环
}
}
}
return true;
}
//*********SPFA算法---优化后的BF算法********
int num[MAXV]; //若明确无负环,可不要这一步
bool SPFA(int s) {
memset(num, 0, sizeof(num));
memset(inq, false, sizeof(inq));
//初始化最短路径为INF
for (int i = 0; i < MAXV; ++i)
d[i] = INF;
//源点入队
std::queue<int> q;
q.push(s);
num[s]++;
d[s] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false; //认为不在队列里面了
for (int j = 0;j < Adj[u].size();++j) {
int v = Adj[u][j].v;
int w = Adj[u][j].w;
if (d[u] + w < d[v]) {
d[v] = d[u] + w; //还存在松弛
if (!inq[v]) { //若v不在队列中
q.push(v);
inq[v] = true;
num[v]++;
if (num[v] >= n) return false; //有可达负环
}
}
}
}
return true;
}
//*********Floyd算法************
//O(n^3),不超过200使用
int dis[MAXV][MAXV]; //只用邻接矩阵表示
void Floyd() {
for (int k = 0; k < n; k++)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (dis[i][k] != INF && dis[k][j] != INF && dis[i][k] + dis[k][j] < dis[i][j])
dis[i][j] = dis[i][k] + dis[k][j];
}
}
}
}
//*********prim算法************
typedef std::pair<int, int> P; //1:距离,2:编号
int ds[MAXV]; //顶点到集合s的距离
bool vis[MAXV] = { false }; //是否收录到集合s中
int prim() { //默认0点为起点
for (int i = 0; i < n; ++i) ds[i] = INF;
ds[0] = 0;
int ans = 0; //最小生成树的边权之和
std::priority_queue<P, std::vector<P>, std::greater<P> > q;
q.push(P(ds[0], 0));
while (!q.empty()) {
int u;
do
{
P p = q.top();
q.pop();
u = p.second;
} while (vis[u]); //关键操作!
//if (p.first > ds[u]) continue;
vis[u] = true;
ans += ds[u];
for (int j = 0; j < Adj[u].size(); ++j) {
int vnow = Adj[u][j].v;
if (!vis[vnow] && Adj[u][j].w < ds[vnow]) {
ds[vnow] = Adj[u][j].w;
q.push(P(ds[vnow], vnow));
}
}
}
return ans;
}
//*********kruskal算法************
struct edge {
int u, v;
int cost; //边权
}E[MAXV];
bool cmp(edge &a, edge &b) {
return a.cost < b.cost;
}
int father[MAXV]; //并查集!!!
int findFather(int x) {
//很牛逼的路径压缩
if (father[x] < 0) return x;
else return father[x] = findFather(father[x]);
}
int kruskal(int n, int m) { //n为顶点数,m为边数
int ans = 0, num_edge = 0; //边权和,边数
memset(father, -1, sizeof(int)*n);
std::sort(E, E + n, cmp); //这是很好的操作吗?
//还可以用最小堆
for (int i = 0; i < n; ++i) {
int faU = findFather(E[i].u);
int faV = findFather(E[i].v);
if (faU != faV) {
father[faU] = faV; //这里就略去归并操作了
ans += E[i].cost;
num_edge++;
if (num_edge == n - 1) break;
}
}
if (num_edge != n - 1) return -1; //无法连通
else return ans;
}
//*********拓扑排序************
int inDegree[MAXV];
bool topological_sort() {
int num = 0;
std::queue<int> q;
for (int i = 0; i < n; ++i) {
if (!inDegree[i])
q.push(i); //入度为0入队列
}
while (!q.empty()) {
int u = q.front();
printf("%d", u);
q.pop();
for (int i = 0; i < Adj[u].size(); ++i) {
int v = Adj[u][i].v;
inDegree[v]--; //后继节点入度减一
if (!inDegree[v])
q.push(v);
}
Adj[u].clear();
num++;
}
if (num == n) return true;
else return false;
}
//*********关键活动************
#include <stack>
//有点难= =
int ve[MAXV];
int vl[MAXV];
std::stack<int> topOrder; //供逆拓扑使用
bool topological_sort2() {
std::queue<int> q;
for (int i = 0; i < n; ++i) {
if (inDegree[i] == 0)
q.push(i);
}
while (!q.empty())
{
int u = q.front();
q.pop();
topOrder.push(u);
for (int i = 0; i < Adj[u].size(); ++i) {
int v = Adj[u][i].v;
if (ve[u] + Adj[u][i].w > ve[v])
ve[v] = ve[u] + Adj[u][i].w;
}
}
if (topOrder.size() == n) return true;
else return false;
}
int CriticalPath() {
memset(ve, 0, sizeof(ve));
if (!topological_sort2()) return -1;
for (int i = 0; i < n; ++i) {
vl[i] = ve[n - 1];
}
//逆拓扑序列
while (!topOrder.empty()) {
int u = topOrder.top();
topOrder.pop();
for (int i = 0; i < Adj[u].size(); ++i) {
int v = Adj[u][i].v;
if (vl[v] - Adj[u][i].w < vl[u])
vl[u] = vl[v] - Adj[u][i].w;
}
}
for (int u = 0; u < n; ++u) {
for (int i = 0; i < Adj[u].size(); ++i) {
int v = Adj[u][i].v, w = Adj[u][i].w;
int e = ve[u], l = vl[u] - w;
if (e == l)
printf("%d->%d", u, v);
}
}
return ve[n - 1]; //返回关键路径长度
}
priority_queue那块写繁了,可以不用pair