函数实现图的基本算法
表示图的不同方式
- 邻接矩阵(缺点:要在开始前说明顶点的个数)
- 邻接表
如何使用邻接矩阵建立模型中的图中加边
在边i和j之间添加一条边,设M(i,j) = 1,这里 M 是图 G 的邻接矩阵
int a[10][10] = {0};
void addedge(int start, int end)
{
if(a[start][end] == 0;
a[start][end] = 1;
}
删除边操作
void remove(int start, int end)
{
a[start][end] == 0;
}
检测两个节点之间是否存在一条路径
int path[max][max] = {0};
void getpath()
{
int cr = max;
int cc = max;
int i,j,k;
for(i = 0; i < max; i++)
for(j = 0; j < max; j++)
for(k = 0; k < max; k++)
path[i][j] += a[i][k] * a[k][j];
}
如何检测图是否是一棵树
int tree(int a[max][max])
{
int i , j;
for(i = 0; i < max ; i++)
for( j = 0; j < max; j++)
if(a[i][j] > 0 && a[j][i] > 0)
return 0;
return 1;
Prim 算法
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。
算法实现步骤
- 选择任意顶点
- 将所选顶点
- 重复步骤4,5,直到在所有顶点都在生成树中为止
- 找到一个具有最小边长但还没有在生成树中的顶点
- 把这个顶点添加到生成树中
- 所有顶点都在生成树中,停止算法
代码实现 C语言
#include<stdio.h>
#include<stdlib.h>
#define max 1000000000;
inta[1005][1005],d[1005],p[1005];
int main()
{
int i,j,k,m,n,min,ans,t;
int x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
a[x][y]=z;
a[y][x]=z;
}
for(i=1;i<=n;i++)
d[i]=1000000000;
d[1]=0;
for(i=2;i<=n;i++)
{
min=max;
for(j=1;j<=n;j++)
if(!p[j]&&min>d[j])
min=d[j];
t=j;
}
p[t]=j;
for(j=1;j<=n;j++)
if(a[t][j]=0&&d[j]>a[t][j])
{
d[j]=a[t][j];
ans+=min;
}
printf("%d",ans);
return0;
}
Kruskal算法
Kruskal算法是一种用来查找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪心算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。
问题一 对图的所有边按照权值大小进行排序。
问题二 将边添加到最小生成树中时,怎么样判断是否形成了回路。
问题一很好解决,采用排序算法进行排序即可。
问题二,处理方式是:记录顶点在"最小生成树"中的终点,顶点的终点是"在最小生成树中与它连通的最大顶点"(关于这一点,后面会通过图片给出说明)。然后每次需要将一条边添加到最小生存树时,判断该边的两个顶点的终点是否重合,重合的话则会构成回路。
算法实现步骤
1.新建图G,G中拥有原图中相同的节点,但没有边;
2.将原图中所有的边按权值从小到大排序;
3.从权值最小的边开始,如果这条边连接的两个节点于图G中不在同一个连通分量中,则添加这条边到图G中;
4.重复3,直至图G中所有的节点都在同一个连通分量中。
c语言实现
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int M = 1e5+7;
struct node
{
int a,b,val;
} Q[M];
int fa[M];
int Rd()
{
int res=0;char c;
while(c=getchar(),!isdigit(c));
do {
res=(res<<3)+(res<<1)+(c^48);
} while(c=getchar(),isdigit(c));
return res;
}
bool cmp(LZ a,LZ b){
return a.val<b.val;
}
int getfa(int v){
if(fa[v]!=v)fa[v]=getfa(fa[v]);
return fa[v];
}
int main()
{
int i,j,n,m,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
Q[i].a=Rd();Q[i].b=Rd();Q[i].val=Rd();
}
sort(Q+1,Q+m+1,cmp);
for(i=1;i<=n;i++)
{
fa[i]=i;
}
int sum=0,cut=0;
for(i=1;i<=m;i++)
{
x=getfa(Q[i].a);
y=getfa(Q[i].b);
if(x==y)continue;
sum+=Q[i].val;
if(++cut==n-1)break;
fa[x]=y;
}
printf("%d",sum);
return 0;
}
使用Warshall算法得到最短路
int minoftwo(int a,int b)
{
if(a == b)
return a;
else
return a>b?a:b;
}
void path(int adj[max][max])
{
int i,j,k;
int q[max][max] = {0};
for(i = 0; i < max; i++)
{
for(j = 0 ; j < max; j++)
{
if(adj[i][j] == 0)
q[i][j] = INF;
else
q[i][j] = adj[i][j];
}
}
for(k = 0; k < max; k++)
{
for(i = 0; i < max; i++)
{
for(j = 0; j < max; j++)
{
q[i][j] = minoftwo( q[i][j],q[i][k]+q[k][j]);
}
}
}
}
DFS 算法
实现靠栈
应用
1.找出图中所有连接部件
2.找出一个链接部件内所有结点
3.求解迷宫问题
举例
SDUT OJ DFS
BFS 算法
实现靠队列
应用
1.prim 的MST算法
2.Dijkstra 的单元最短路径算法
3.复制集合,Cheney算法
4.构建Web搜索代理
举例
SDUT OJ BFS