用于看文字描述后容易写出相对应的图论代码
这篇文章倾向于自用-代码是手撸源码,可以运行
图论的解析
**
dijkstra
**
1.设置初始点为true
2.初始点更新 「直接使用map中的行更新」
3.在剩下的顶点中选最小的顶点v
4.先设为true
5.使用顶点v更新「用dist数组中v+map中v行<dist数组i顶点」
#include<iostream>
#include<algorithm>
#include<cstring>
#include<climits>
using namespace std;
const int N=100;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/*
------------------- Dijkstra -----------------------------
从点A到其它所有点的最短路径
*/
int map[N][N]; //邻接矩阵表示图
bool boo[N];
int dis[N];
int a,b;
int c=0;
int foot[N];
int key1,key2,value;
void dijkstra(int key){
foot[c++]=key;
boo[key]=1;
dis[key]=0;
int tag=key;
for(int i=0;i<a-1;++i){ //仅仅是枚举次数
//更新dis
for(int k1=0;k1<a;k1++){
if(map[tag][k1]!=0 && map[tag][k1]!=INT_MAX && boo[k1]==0 ){ //当前k1需要更新
cout<<"dis[k1]:"<<dis[k1]<<endl;
cout<<"dis[tag]:"<<dis[tag]<<endl;
//1. 当 dis=无穷
//2. 当有值 外来的比原来的小
if(dis[k1]==INT_MAX|| dis[tag]+map[tag][k1]<dis[k1]){
dis[k1]=dis[tag]+map[tag][k1];
}
}
}
//打印dis
cout<<"dis:"<<endl;
for(int k=0;k<a;k++){
cout<<dis[k]<<" ";
}
cout<<endl;
//找最小的路径
cout<<"next:"<<endl;
int next=INT_MAX;
for(int j=0;j<a;j++){
if(boo[j]!=1 && dis[j]!=0 && dis[j]<next){
next=dis[j];
tag=j;
}
}
cout<<"tag:"<<tag<<endl;
boo[tag]=1;
foot[c++]=tag;
}
//打印路径
cout<<endl;
cout<<"foot:"<<endl;
for(int i=0;i<a;i++){
cout<<foot[i]<<"-";
}
//打印数值
cout<<"dis:"<<endl;
for(int i=0;i<a;i++){
cout<<dis[i]<<"-";
}
}
int main(int argc, char *argv[]) {
int G[6][4];
fill(G[0],G[0]+6*4,520);
for(int i=0;i<6;i++){
for(int j=0;j<4;j++){
cout<<G[i][j]<<" ";
}
cout<<endl;
}
cout<<"请输入顶点数和边数:例如 5 6"<<endl;
cin>>a>>b;
fill(map[0],map[0]+N*N,INT_MAX);
fill(dis,dis+a,INT_MAX);
for(int i=0;i<b;i++){
cin>>key1>>key2>>value;
map[key1][key2]=value;
map[key2][key1]=value;
}
for(int i=0;i<b;i++){
for(int j=0;j<b;j++){
if(i==j){
map[i][j]=0;
break;
}
}
}
cout<<"show map:"<<endl;
for(int i=0;i<b;i++){
for(int j=0;j<b;j++){
cout<<map[i][j]<<" ";
}
cout<<endl;
}
dijkstra(0);
return 0;
}
**
floyd
**
1.用所有顶点更新图「二维数组」
2.「当前顶点v iv+vj<ij 则更新」「同时更新 路径ij=v」
3.路径打印使用递归回溯
路径解析:
一开始二维数组所有所有设为-1
更新路径v时说明不是直接通路 是需要桥梁
只有时-1的时候才是直接通路相连的,输出u,v
不是-1则时中间点 递归 左边 递归右边
#include <iostream>
#include <algorithm>
#include <limits.h>
using namespace std;
const int N=100;
int map[N][N];
void init()
{
for(int i=0; i<N; i++)
{
for(int j=0; j<N; j++)
{
map[i][j]=9999;
}
}
}
void floyd(int n)
{
int i,j,k;
for(int k=0;k<n;k++)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i!=j)
map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
}
}
}
}
void PMap(int n)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<map[i][j]<<" ";
}
cout<<endl;
}
}
int main()
{
int n,v;
init();
cout<<"请输入顶点数和边数:"<<endl;
cin>>n>>v;
PMap(n);
int key1,key2,cost;
for(int i=0;i<v;i++)
{
cin>>key1>>key2>>cost;
map[key1][key2]=map[key2][key1]=cost;
}
cout<<"input:"<<endl;
PMap(n);
floyd(n);
cout<<"AA:"<<endl;
PMap(n);
return 0;
}
DFS && BFS
遍历图
都要直接遍历所有顶点函数:原因是避免非连通图,不相连的顶点没有遍历
BFS:
从一个顶点v开始
把v顶点的邻接点放入queue中
出队一个,打印一个 重复操作
直到队列为空
#include <iostream>
#include <queue>
#include <cstdlib>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/*
注意 遇到不连通的图 (类似森林的图) 要加一个BFStravel函数 因为会遍历不到另一个连通块
从这个函数开始 而不是BFS函数
void BFSTravel()
{
for(所有顶点)
if(!vis)
BFS()
}
*/
int map[5][5]={
{0,1,0,1,0},
{1,0,1,0,1},
{0,1,0,0,0},
{1,0,0,0,0},
{0,1,0,0,0}
};
bool bmap[5];
queue<int> q;
int count=0;
int foot[5];
void bfs(){
while(!q.empty()){
int key=q.front();
q.pop();
for(int i=0;i<5;i++){
if(bmap[i]==false && map[key][i]==1){
cout<<i+1<<endl;
bmap[i]=true;
foot[count++]=i;
q.push(i);
if(count==5){
exit(0);
}
}
}
}
}
int main(int argc, char *argv[]) {
int key=4; //数组从0开始 4实际是5
bmap[key]=true;
foot[count++]=key;
q.push(key);
bfs();
for(int i=0;i<5;i++){
cout<<foot[i]<<"-";
}
cout<<endl;
return 0;
}
DFS:
出口 count==n
key
找邻接点key i==1 「通路」
找到马上递归DFS i 找下一个邻接点
#include <iostream>
#include <cstdlib>
using namespace std;
/*
注意 遇到不连通的图 (类似森林的图) 要加一个DFStravel函数 因为会遍历不到另一个连通块
从这个函数开始 而不是DFS函数
void DFSTravel()
{
for(所有顶点)
if(!vis)
DFS()
}
*/
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int map[5][5]={
{0,1,0,1,0},
{1,0,1,0,1},
{0,1,0,0,0},
{1,0,0,0,0},
{0,1,0,0,0}
};
bool bmap[5];
int foot[5];
int count=0;
void dfs(int key){
foot[count++]=key;
if(count==5){
exit(0);
}
bmap[key]=true;
for(int i=0;i<5;i++){
if(bmap[i]==false && map[key][i]==1){
cout<<i+1<<endl;
dfs(i);
}
}
}
int main(int argc, char *argv[]) {
dfs(2); //从零开始 所以这个应该是实际的3
for(int i=0;i<5;i++){
cout<<foot[i]<<"-";
}
cout<<endl;
return 0;
}
Kruscal:
find函数
union函数
father数组
边集
如果没有顶点编号,给的是坐标,需要自动生成边集,则使用一个顶点 连n个顶点双循环
顶点编号使用i j
for( i=0;i<n;i++)
for(j=i+1; j<n;j++)
E[num].u=i; E[num].v=j;
E[num].cost=[计算];
num++;
num就是边的数量
sort 边集就可以使用kruscal算法了
#include <iostream>
#include<algorithm>
using namespace std;
const int N=1000;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct EDGE{
int u,v,cost;
void set(int a,int b,int w){
u=a;
v=b;
cost=w;
}
};
EDGE edge[N*N-1/2];
bool cmp(EDGE a, EDGE b){
return a.cost<b.cost;
}
int father[N];
int find(int x){
if(father[x]==-1){
return x;
}else{
return father[x]=find(father[x]);
}
}
bool union1(int x ,int y){
x=find(x);
y=find(y);
if(x==y){
return false;
}
if(x>y){
father[x]=y;
}else{
father[y]=x;
}
return true;
}
int main(int argc, char *argv[]) {
int i;
int v,w,cost;
cout<<"请输入边数和顶点数:"<<endl;
int m,t;
cin>>m>>t;
cout<<"请输入边的信息 例如 1 2 10:"<<endl;
for(i=0;i<m;i++){
cin>>v>>w>>cost;
edge[i].set(v,w,cost);
}
sort(edge,edge+m,cmp);
i=0;
fill(father,father+m,-1);
int sum=0,count=0;
while(count!=t-1){
if(union1(edge[i].u,edge[i].v)){
cout<<edge[i].u<<"-"<<edge[i].v<<endl;
sum+=edge[i].cost;
count++;
}
i++;
}
cout<<"sum:"<<sum <<endl;
return 0;
}
**
Prim:
**
1.先从一个顶点v开始 先设置为true
2.更新cost数组
3.进循环 直到count==n-1「所有顶点纳入图中」
4.选最小 并设置true
5.更新cost数组
#include<bits/stdc++.h>
using namespace std;
const int adjacent_matri_max=1000;
int vertex_num,edge_num; //顶点数量 边数量
int price=0; //最小生成树代价
int adjacent_matri[adjacent_matri_max][adjacent_matri_max]; //邻接矩阵
bool visitied[adjacent_matri_max]; //定义标记数组
int l_cost[adjacent_matri_max];
int path[adjacent_matri_max];
//初始化邻接矩阵INT_MAX
void init(){
for(int i=0;i<vertex_num;i++){
for(int j=0;j<vertex_num;j++){
adjacent_matri[i][j]=INT_MAX;
}
}
fill(visitied,visitied+vertex_num,false);
fill(l_cost,l_cost+vertex_num,INT_MAX);
return ;
}
//Prim算法实现最小生成树
void Prim(int key){
//key 0-vertex
int k=0;
path[k++]=key;
do{
visitied[key]=true; //先把顶点设为访问
for(int i=0;i<vertex_num;i++){ //更新代价数组
l_cost[i]=min(l_cost[i],adjacent_matri[key][i]);
}
int min_cost=INT_MAX;
//找到之后下一轮才给路径
for(int i=0;i<vertex_num;i++){
if(visitied[i]==false && l_cost[i]<min_cost){
min_cost=l_cost[i];
key=i;
}
}
price+=min_cost;
path[k]=key;
cout<<k+1<<":"<<endl;
cout<<"mint_cost:"<<min_cost<<endl;
cout<<"price:" <<price<<endl<<endl;
}while(++k<vertex_num);
return;
}
void PrintTree(int key){
cout<<"最小生成树生成顺序:"<<endl;
// cout<<key<<"->";
int count=0;
for(int i=0;i<vertex_num;i++){
// if(key!=path[i]){
cout<<path[i]<<" ";
// if(count++!=vertex_num-2)
// cout<<"->";
// }
}
}
int main(){
int row,col;
int key;
int weight;
cout<<"现在开始构造图:"<<endl;
cout<<"请输入顶点数量:"<<endl;
cin>>vertex_num;
cout<<"请输入边的数量:"<<endl;
cin>>edge_num;
//初始化矩阵为INT最大值
init();
//生成图(邻接矩阵)
cout<<"请输入边(两个顶点表示)和边的权值:(共"<<edge_num<<"组(行))"<<endl;
for(int i=0;i<edge_num;i++){
cin>>row>>col;
cin>>weight;
adjacent_matri[row][col]=adjacent_matri[col][row]=weight;
}
for(int i=0;i<vertex_num;i++){
for(int j=0;j<vertex_num;j++){
cout<<adjacent_matri[i][j]<<" ";
}
cout<<endl;
}
cout<<"请输入起点顶点:"<<endl;
cin>>key;
Prim(key);
cout<<"最小生成树代价为:"<<price<<endl;
PrintTree(key);
return 0;
}
topologicalsort
:
1.把所有indegree为0的顶点入队
2.当队不为空
获取队头元素,并出队,记录。
使用队头元素找到相邻的边后 使该点入度-1
判断indegree为0入队
--------- 当count为n时 拓扑成功-----------否则 失败 因:成环
#include <iostream>
#include <algorithm>
#include <limits.h>
using namespace std;
const int N=100;
int map[N][N];
int vis[N];
void topsort(int n)
{
int in;
//所有顶点依次去除
for(int i=0;i<n;i++)
{
//先找一个入度为0的节点;
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
//纵坐标为入度
if(!vis[k])
{
vis[k]=-1;
in=k;
cout<<k<<endl;
break;
}
}
}
//使用当前入度为0 的 in点 把所有以此点为入度的点 入度--
for(int i=0;i<n;i++)
{
if(map[in][i]==1)
{
vis[i]--; //入度--
map[in][i]=0; //且不可达了
}
}
}
}
int main()
{
int n,v;
cout<<"请输入顶点数和边数:"<<endl;
cin>>n>>v;
int key1,key2;
for(int i=0;i<v;i++)
{
cin>>key1>>key2;
map[key1][key2]=1; //key1->key2
vis[key2]++; //key2入度+1
}
topsort(n);
return 0;
}
求点赞👍👍👍
原创不易,点赞容易。
您的鼓励就是我的最大动力!!!。
本篇博客到此结束,谢谢大家观看。