图的算法及函数操作

表示图的不同方式

  1. 邻接矩阵(缺点:要在开始前说明顶点的个数)
  2. 邻接表

如何使用邻接矩阵建立模型中的图中加边

在边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算法、亚尔尼克算法或普里姆-亚尔尼克算法。

算法实现步骤

  1. 选择任意顶点
  2. 将所选顶点
  3. 重复步骤4,5,直到在所有顶点都在生成树中为止
  4. 找到一个具有最小边长但还没有在生成树中的顶点
  5. 把这个顶点添加到生成树中
  6. 所有顶点都在生成树中,停止算法
代码实现 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值