特殊矩阵的压缩存储
对称矩阵的压缩存储
只存储主对角线+上\下半角
按照行优先或者列优先存储
三角矩阵的压缩存储
跟对称矩阵相同的思想
稀疏矩阵的压缩存储
- 三元组方式存储
- 十字链表法
图的基本概念
图G比顶点集边集日且成,记为G=(V,E),其中v(G)表示图G中顶点的有限非空集;E(G)表示图G中顶点之间的关系(边)集合。若V={v, vs… , vn,},则用V]表示图G中顶点的个数,也称图G的阶,E= {(u, v) | ueV,vev},用|E|表示图G中边的条数。
最小生成树
Prim算法
从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。
Kruskal算法
每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选)直到所有结点都连通
最短路径
BFS(无权图) 单源最短路径
Dijkstra(带权图, 无权图) 单源最短路径 不适合带负权的图
Floyd(带权图,无权图) 各顶点间的最短路径 不能解决带负权回路的图
拓扑排序
AOV网(Activity on vertex Network,用顶点表示活动的网)
用DAG图〈有向无环图)表示一个工程。顶点表示活动,有向边<Vi,Vj>表示活动Vi必须先于活动Vj进行
拓扑排序︰在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:
1每个顶点出现且只出现一次。2若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径。 或定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。
逆拓扑排序:先删除入度为0的点
在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销〈如完成活动所需的时间),称之为用边表示活动的网络,简称AOE网(Activity On Edge NetWork)
关键路径
AOE网具有以下两个性质︰
①只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始; ②只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。另外,有些活动是可以并行进行的
在AOE网中仅有一个入度为0的顶点,称为开始顶点(源点),它表示整个工程的开始;
也仅有一个出度为0的顶点,称为结束顶点(汇点),它表示整个工程的结束。
从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动
Graph.h
#ifndef _GRAPH_H_
#define _GRAPH_H_
#include <iostream>
#include <vector>
//无向图,邻接矩阵
class UMGraph
{
public:
UMGraph(const int v, const int e) : __INF(99999999)
{
this->vertex = v;
this->edge = e;
for(int i = 0; i <= vertex; ++ i)
visited.push_back(false);
for(int i = 0; i <= vertex; ++ i)
graph.push_back(std::vector<int>(vertex+1, __INF));
// for(int i = 1; i <= vertex; ++ i)
// graph[i][i] = 0;
}
public:
int getV(){ return vertex; }
int getE(){ return edge; }
void getGraph();
public:
void Insert();
bool Delete();
void DFSTravel(std::vector<int> &);
void BFSTravel(std::vector<int> &);
void Dijkstra(std::vector<int> &, std::vector<int> &);
void Dijkstraheap(std::vector<int> &, std::vector<int> &);
void Prim(int &cost, bool flag = 1);
void Primheap(int &cost, bool flag = 1);
void Kruskal(int &cost);
private:
void __Insert(const int u, const int v, const int weight);
bool __Delete(const int u, const int v);
void __DFSTravel(const int u, std::vector<int> &);
void __BFSTravel(const int u, std::vector<int> &);
void __Dijkstra(const int u, std::vector<int> &, std::vector<int> &);
void __Dijkstraheap(const int u, std::vector<int> &, std::vector<int> &);
void __Prim(int &cost, bool flag);
void __Primheap(int &cost, bool flag);
int find_father(int x, std::vector<int> &fat);
void __Kruskal(int &cost);
public:
int vertex, edge;
const long long __INF;
std::vector<bool> visited;
std::vector<std::vector<int> > graph;
};
//无向图,邻接表
//有向图,邻接矩阵
//有向图,邻接表
#endif //_GRAPH_H_
Graph.cpp
#include "Graph.h"
#include <iostream>
#include <queue>
#include <algorithm>
void UMGraph::getGraph()
{
for(int i = 1; i <= vertex; ++ i)
{
for(int j = 1; j <= vertex; ++ j)
std::cout << graph[i][j] << " ";
std::cout << std::endl;
}
}
void UMGraph::Insert()
{
std::cout << "Input your node v form u and weight: ";
int un, vn, w;
std::cin >> un >> vn >> w;
__Insert(un, vn, w);
}
void UMGraph::__Insert(const int u, const int v, const int weight)
{
//int tmp = std::min(weight, graph[u][v]);
graph[u][v] = graph[v][u] = std::min(weight, graph[u][v]);
}
bool UMGraph::Delete()
{
std::cout << "Input you'll delete two nodes: ";
int un, vn;
std::cin >> un, vn;
return __Delete(un, vn);
}
bool UMGraph::__Delete(const int u, const int v)
{
if(graph[u][v] != __INF && graph[v][u] != __INF)
{
return false;
}
graph[u][v] = graph[v][u] = __INF;
return false;
}
void UMGraph::DFSTravel(std::vector<int> &p)
{
std::cout << "Input you'll DFSTravel first node: ";
int un;
std::cin >> un;
for(auto x : visited)
x = false;
//std::cout << "The DFS sequence is: \n";
__DFSTravel(un, p);
//std::cout << "\n";
}
void UMGraph::__DFSTravel(const int u, std::vector<int> &p)
{
visited[u] = true;
//std::cout << u << " ";
p.push_back(u);
for(int i = 1; i <= vertex; ++ i)
{
if(!visited[i] && graph[u][i] != __INF && graph[i][u] != __INF)
{
visited[i] = true;
__DFSTravel(i, p);
}
}
}
void UMGraph::BFSTravel(std::vector<int> &p)
{
std::cout << "Input you'll BFSTravel first node: ";
int un;
std::cin >> un;
for(auto x : visited)
x = false;
//std::cout << "The BFS sequence is: \n";
__BFSTravel(un, p);
//std::cout << "\n";
}
void UMGraph::__BFSTravel(const int u, std::vector<int> &p)
{
//std::cout << u << " ";
p.push_back(u);
std::queue<int> q;
q.push(u);
visited[u] = 1;
while(!q.empty())
{
int t = q.front();
q.pop();
for(int i = 1; i <= vertex; ++ i)
{
if(!visited[i] && graph[t][i] != __INF && graph[i][t] != __INF)
{
visited[i] = true;
q.push(i);
//std::cout << i << " ";
p.push_back(i);
}
}
}
}
void UMGraph::Dijkstra(std::vector<int> &dis, std::vector<int> &path)
{
std::cout << "Input you'll begin from: ";
int un;
std:: cin >> un;
dis.push_back(0);
path.push_back(0);
for(int i = 1; i <= vertex; ++ i)
{
dis.push_back(graph[un][i]);
visited[i] = false;
if(dis[i] == __INF)
path.push_back(-1);
else
path.push_back(un);
}
dis[un] = 0;
visited[un] = true;
__Dijkstra(un, dis, path);
//std::cout << "The shortest dis from u to other is: \n";
// for(auto x : dis)
// std::cout << x << " ";
// std::cout << "\n";
// for(auto x : path)
// std::cout << x << " ";
// std::cout << "\n";
// for(int i = 1; i <= vertex; ++ i)
// std::cout << dis[i] << " ";
// std::cout << "\n";
// for(int i = 1; i <= vertex; ++ i)
// std::cout << path[i] << " ";
// std::cout << "\n";
}
void UMGraph::__Dijkstra(const int u, std::vector<int> &dis, std::vector<int> &path)
{
for(int i = 1; i <= vertex; ++ i)
{
int t = u, tmp = __INF;
for(int j = 1; j <= vertex; ++ j)
if(!visited[j] && tmp > dis[j])
{
tmp = dis[j];
t = j;
}
if(t == vertex) break;
visited[t] = true;
for(int j = 1; j <= vertex; ++ j)
{
if(!visited[j] && graph[t][j] < __INF)
{
if(dis[j] > dis[t]+graph[t][j])
{
dis[j] = dis[t]+graph[t][j];
path[j] = t;
}
}
}
}
}
void UMGraph::Dijkstraheap(std::vector<int> &dis, std::vector<int> &path)
{
std::cout << "Input you'll begin from: ";
int un;
std:: cin >> un;
//占位
dis.push_back(0);
path.push_back(0);
//初始化
for(int i = 1; i <= vertex; ++ i)
{
dis.push_back(__INF);
visited[i] = false;
if(dis[i] == __INF)
path.push_back(-1);
else
path.push_back(un);
}
dis[un] = 0;
__Dijkstraheap(un, dis, path);
//std::cout << "The shortest dis from u to other is: \n";
// for(auto x : dis)
// std::cout << x << " ";
// std::cout << "\n";
// for(auto x : path)
// std::cout << x << " ";
// std::cout << "\n";
// for(int i = 1; i <= vertex; ++ i)
// std::cout << dis[i] << " ";
// std::cout << "\n";
// for(int i = 1; i <= vertex; ++ i)
// std::cout << path[i] << " ";
// std::cout << "\n";
}
void UMGraph::__Dijkstraheap(const int u, std::vector<int> &dis, std::vector<int> &path)
{
typedef struct Node
{
int u, step;
Node() {};
Node(int a, int b) : u(a), step(b) {};
bool operator<(const Node &t) const
{
return step > t.step;
}
}Node;
std::priority_queue<Node> pq;
pq.push(Node(u, 0));
while(!pq.empty())
{
Node it = pq.top();
pq.pop();
int t = it.u;
if(visited[t]) continue; //找到了
visited[t] = 1;
for(int i = 1; i <= vertex; ++ i)
{
if(!visited[i] && graph[t][i] < __INF)
{
if(dis[i] > dis[t]+graph[t][i])
{
dis[i] = dis[t]+graph[t][i];
path[i] = t;
pq.push(Node(i, dis[i]));
}
}
}
}
}
void UMGraph::Prim(int &cost, bool flag)
{
__Prim(cost, flag);
}
void UMGraph::__Prim(int &cost, bool flag)
{
std::vector<int> lowcost(vertex+1, 0), mit(vertex+1, 1);
for(int i = 1; i <= vertex; ++ i)
{
lowcost[i] = graph[1][i];
mit[i] = 1;
}
mit[1] = 0;
int idx = 1;
cost = 0;
for(int i = 2; i <= vertex; ++ i)
{
int minn = __INF, t = 0;
for(int j = 2; j <= vertex; ++ j)
{
if(lowcost[j] < minn && lowcost[j] != 0)
{
minn = lowcost[j];
t = j;
}
}
if(flag == 1)
{
printf("%d --> %d w: %d\n", mit[t], t, minn);
}
cost += minn;
lowcost[t] = 0;
for(int j = 2; j <= vertex; ++ j)
{
if(graph[t][j] < lowcost[j])
{
lowcost[j] = graph[t][j];
mit[j] = t; //更新前驱
}
}
}
}
void UMGraph::Primheap(int &cost, bool flag)
{
__Primheap(cost, flag);
}
void UMGraph::__Primheap(int &cost, bool flag)
{
typedef struct node
{
int weight, u;
node(int w, int u1) : weight(w), u(u1) {};
bool operator<(const node &a) const
{
return weight > a.weight;
}
}node;
std::vector<int> path(vertex+1, -1);
path[1] = 1;
std::vector<int> lowcost(vertex+1, __INF);
for(int i = 0; i <= vertex; ++ i)
{
visited[i] = 0;
lowcost[i] = __INF;
}
cost = 0;
std::priority_queue<node> pq;
pq.push(node(0, 1));
while(!pq.empty())
{
node t = pq.top();
pq.pop();
int d = t.weight, v = t.u;
if(visited[v]) continue;
visited[v] = true;
cost += d;
for(int i = 1; i <= vertex; ++ i)
{
if(!visited[i] && lowcost[i] > graph[v][i])
{
lowcost[i] = graph[v][i];
pq.push(node(lowcost[i], i));
path[i] = v;
}
}
}
if(flag == 1)
{
for(int i = 1; i <= vertex; ++ i)
std::cout << path[i] << " ";
std::cout << "\n";
}
}
int UMGraph::find_father(int x, std::vector<int> &fat)
{
if(fat[x] != x)
return find_father(fat[x], fat);
return x;
}
void UMGraph::Kruskal(int &cost)
{
__Kruskal(cost);
}
void UMGraph::__Kruskal(int &cost)
{
std::vector<int> fat(vertex+1, 0);
for(int i = 1; i <= vertex; ++ i)
fat[i] = i;
typedef struct Edge
{
int u, v, w;
bool operator<(const Edge &a) const
{
return w < a.w;
}
}Edge;
Edge arr[edge+1];
int idx = 1;
for(int i = 1; i <= vertex; ++ i)
{
for(int j = i; j <= vertex; ++ j)
{
if(graph[i][j] != __INF)
{
arr[idx].u = i; arr[idx].v = j; arr[idx].w = graph[i][j];
idx ++;
}
}
}
// for(int i = 1; i <= edge; ++ i)
// std::cout << arr[i].u << " " << arr[i].v << " " << arr[i].w << "\n";
std::sort(arr+1, arr+1+edge);
// std::cout << "\n";
// for(int i = 1; i <= edge; ++ i)
// std::cout << arr[i].u << " " << arr[i].v << " " << arr[i].w << "\n";
// std::cout << "\n";
int num = 0;
for(int i = 1; i <= edge; ++ i)
{
if(num == vertex-1) break;
int u, v, w;
u = arr[i].u; v = arr[i].v; w = arr[i].w;
if(find_father(u, fat) != find_father(v, fat))
{
fat[find_father(u, fat)] = find_father(v, fat);
cost += w;
num ++;
}
}
}