图的学习以及两个算法

图的学习

1、图的定义

图是一个由有穷非空集合和顶点之间边的集合组成的,表示为G(V,E)

G表示一个图,V表示图G中顶点的集合,E 是图G中边的集合

2.概念

无向边,Vi到Vj之间的边没有方向,表示:(Vi,Vj)

有向边,Vi到Vj的边有反向,弧

A表示弧尾,D表示弧头,<A,D>表示弧

连通图,V到V‘有路径,则连通,任意都符合

连通分量:无向图中的极大连通子图

强连通图:Vi到Vj和Vj到Vi都存在路径

强连通分量:有向图中极大强大连通子图

生成树:一个连通树的生成树是一个极小的连通子图,它含有图中全部的N个结点,但只有足以构成一棵树的N-1条边

图顶点与边间的关系

有向图中顶点入度为0,其余顶点入度为1的为有向树,一个有向图由若干棵有向树构成生成森林

3.存储结构

邻接矩阵是由 V x V 顶点组成的二维数组,每一行和每一列代表一个顶点。

邻接表数组的索引表示一个顶点,其链表中的每个元素表示与该顶点形成边的其他顶点。

4.图的基本操作

增删改查!四个基本操作

代码实现

板子:

``#include<iostream>`
`#include<queue>`
`using namespace std;`

`const int INF = 0x7fffffff;`
`const int MaxVnum = 100; //顶点最大个数`
`int visist[MaxVnum] = {0};`
`typedef char VexType;//顶点的数据类型`
`typedef int EdgeType;//顶点的边权;若不带权值则用0和1表示其连通性`
`typedef struct {`
	`VexType Vex[MaxVnum];//顶点信息`
	`EdgeType Edge[MaxVnum][MaxVnum];//邻接矩阵`
	`int vexnum, edgenum; //顶点数和边数`
`} Gragh;`

`void dfs(Gragh G, int v) { //假设已经创建了一个图的邻接矩阵G ,v是开始访问的顶点`
	`int w;//w是邻接点`
	`cout << G.Vex[v] << endl;`
	`for (w = 0; w < G.vexnum; w++) { //遍历所有顶点`
		`visist[v] = 1; //访问过了标记为真` 
		`if (G.Edge[v][w] && !visist[w]) dfs(G, w); //邻接且未被访问过,则递归访问其邻接点`
	`}`
`}`

`void bfs(Gragh G, int v) {`
	`int u, w;`
	`queue<int>Q;`
	`visist[v] = 1;`
	`cout << G.Vex[v] << endl;`
	`Q.push(v);//顶点v入队`
	`while (Q.empty() == 0) { //如果队列不空`
		`u = Q.front(); //队列的头元素出列赋给u`
		`Q.pop();//队列头元素出队`
		`for (w = 0; w < G.vexnum; w++) {`
			`if (G.Edge[u][w] && !visist[w]) { //u,w邻接且w未被访问过`
				`cout << G.Vex[w] << endl;`
				`visist[w] = 1;`
				`Q.push(w);//领接点加入队列`
			`}`
		`}`
	`}`
`}` 

`int main(){`
	`Gragh g;`
	`cout << "请输入此图的顶点数和边数" << endl;`
	`cin >> g.vexnum >> g.edgenum;`
	`getchar();`
	`cout << "请输入此图的顶点" << endl;`
	`for(int i = 0; i < g.vexnum; i++){`
		`cin >> g.Vex[i];`
	`}`
	`cout << "请输入关于此图的边信息" << endl;`
	`for(int i = 0; i < g.vexnum; i++){`
		`for(int j = 0; j < g.vexnum; j++){`
			`cin >> g.Edge[i][j];`
		`}`
	`}`
``	
`//	dfs(g,0);`
	 ``
`//	bfs(g,0);`

``	




	return 0;

`}``

#### 5.dfs/bfs

这个上次在,最短路径问题以及提及,在此不做多余赘述

板子:Prim算法(选点)和Kruskal算法(选边)

#include<stdio.h>
int map[5010];
int dis[5010];
int max=1999999;
int maps[5010][5010];
long long sum;
long long min;
int hh=0;
int next;
void beg(int a){
for(int hg=1;hg<=a;hg++)
{
    for(int jk=1;jk<=a;jk++){
        maps[hg][jk]=max;
        maps[jk][hg]=max;
    }
}

}


int main(){
int n,m;//点和边的数量
int a,b,c;//输入的数据
int jl;//就是一个用于循环的变量

scanf("%d%d",&n,&m);
beg(n);

for(int h=1;h<=m;h++){
    scanf("%d%d%d",&a,&b,&c);
    if(c<maps[a][b]){
    maps[a][b]=c;
    maps[b][a]=c;
    }
}


for(int lp=1;lp<=n;lp++)
dis[lp]=maps[1][lp];//1默认为起点

map[1]=1;//起点为用过的
for(int i=1;i<n;i++){
        min=max;
    for(jl=1;jl<=n;jl++)
    {
     if(dis[jl]<min&&map[jl]==0)
     {
       min=dis[jl];
       next=jl;

     }
     
    }
     
    if(min==max){
        printf("orz");
        hh++;
        break;
     
    }
    map[next]=1;
    sum=sum+dis[next];//加上最短的路程
    for(int hj=1;hj<=n;hj++)//对每个点到树的最小的距离进行更新
    {
        if(map[hj]==0&&maps[next][hj]<dis[hj]&&i<n-1)//i<n-1最后一次就不用更新了
        {
            dis[hj]=maps[next][hj];
        }
    }

}
if(hh==0)
printf("%lld",sum);

return 0;
}

#include<stdio.h>
int map[1001000]={0};//为0的就是T标号
long long dis[1001000];
long long max=2147483647;

void bg(int u){//赋初值函数
for(int h=1;h<=u;h++){
    dis[h]=max;
    }
}

struct node{
int to;
int chang;
int next;//上一条是边数据的下标

}nodes[1001000];

long long min(long long jl,long long jk){

if(jl<jk){
    return jl;
}
else{
    return jk;
}

}


int cin;//表示结构体数组的下标(就是一个一个数组的用无实际的意义)

int first[1001000]={0};//保存头的数组(下标就是头!)值的含义是在结构体中保存的边对应的下标
//值表示以这个头开始的最后一条线

void add(int a,int b,int c){
cin++;//用新的来存
nodes[cin].to=b;//to表示到那去(边的终点)
nodes[cin].chang=c;//chang表示边的长度
nodes[cin].next=first[a];//next表示找到上一以a为起点的上以条边的数组的下标
first[a]=cin;//现在a到b变成了以a为起点的最后一条边就改一下first[a]的值(这个值是储存这条边的数组的下标

}
int main()
{
int n,m,k;
int jj,kk,ll;
scanf("%d%d%d",&n,&m,&k);
bg(n);
for(int j=1;j<=m;j++){
    scanf("%d%d%d",&jj,&kk,&ll);
    add(jj,kk,ll);

}
dis[k]=0;
int pos=k;
while(map[pos]==0){
    map[pos]=1;
   for(int i=first[pos];i!=0;i=nodes[i].next){
        if(map[nodes[i].to]==0){
        dis[nodes[i].to]=min(dis[nodes[i].to],dis[pos]+nodes[i].chang);
        }
    }
    long long mine=max;
    for(int y=1;y<=n;y++){
        if(dis[y]<mine&&map[y]==0)
        {
            mine=dis[y];
            pos=y;
        }

    }

}

for(int y=1;y<=n;y++){
    printf("%lld ",dis[y]);
}

return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏生十一_Nojambot

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值