图
图就是右4一些小圆点(称为顶点)和连接这些小圆点的直线(称为边)组成的。
图的遍历有两种方式,什么是遍历呢?遍历就是把每一个顶点都访问一次。每个顶点的访问顺序,称为时间戳。
图分为有向图和无向图,如果给图的每一边规定一个方向,那么得到的图称为有向图,其边称为有向边。在有向图中,与一个点关联的边有出边和入边之分,而与一个有向边关联的两个点也有始点和终点之分。相反没有方向的图称为无向图。
这就是一个图,无向图。
图的遍历有两种方式:
1.深度优先搜索
2.广度优先搜索
深度优先搜索
深度优先搜索的主要思想是:首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未被访问过的顶点:当没有未被访问的顶点时,回到上一个顶点,继续试探访问其他顶点,,知道所有顶点都被访问过。
对上图用深度优先搜索,访问顺序是1->2->4->3->5
用深度优先搜索上图等同于
#include<stdio.h>
int map[100][100];
int map1[100];
int n,a,b,sum=0;
void fun(int x)
{
printf("%d ",x);
sum++;//计数
if(sum==n) return ;//全部搜完了
for(int i=1;i<=n;i++)
{
if(map[x][i]==1&&map1[i]==0)//还没被搜过
{
map1[i]=1;//标记
fun(i);
}
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)map[i][j]=0;//不存在的边
else map[i][j]=100;
}
for(i=1;i<=n;i++)
{
scanf("%d %d",&a,&b);
map[a][b]=1;//因为是无向图所以两边都要
map[b][a]=1;
}
map[1]=1;//标记,已经走过
fun(1);//从顶点1开始搜索
return 0;
}
输入的是n和边
深度优先搜索一般用来求最短路程之类的
那么接下来做个题目吧
输入
第一行输入n城市总数,m公路总数;接下来输入a,b,c,代表一条公路从a到b,路程为c。
输出
从起点到终点的最短路程
#include<stdio.h>
int n,m,a,b,c,k;
int sum[100][100];
int sign[100];
int min=1000;
void fun(int x,int num)
{
if(num>min) return ;//没有搜索的必要
if(x==n)//到达
{
if(num<min)
min=num;
return ;
}
for(int i=1;i<=n;i++)
{
if(sum[x][i]!=100&&sign[i]==0)
{
sign[i]=1;
fun(i,sum[x][i]+num);
sign[i]=0;//方便下一次搜索
}
}
return ;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)sum[i][j]=0;
else sum[i][j]=100;
}
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&c);
sum[a][b]=c;
}
sign[1]=1;
fun(1,0);
printf("%d",min);
return 0;
}
如果把图改成无向图,代码几乎差不多
只需把sum[a][b]=c;这里再加上sum[b][a]=c;
广度优先搜索
广度优先搜索的主要思想:首先以一个为被访问过的顶点作为起始顶点,访问其所有相邻的顶点,然后对每个相邻的顶点,在访问它们的相邻的未被访问过的顶点,知道所有顶点都被访问过。
对刚开始的图用广度优先搜索,访问次序是:1->2->3->5->4;
相当于下图:
#include<stdio.h>
int sum[100][100];
int sign[100],q[100];
int n,a,b,head,tail,x;
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)sum[i][j]=0;
else sum[i][j]=100;
}
for(i=1;i<=n;i++)
{
scanf("%d %d",&a,&b);
sum[a][b]=1;
sum[b][a]=1;
}
sign[1]=1;
head=tail=1;
q[head]=1;
tail++;
while(head<tail)//队不为空时
{
x=q[head];
for(i=1;i<=n;i++)
{
if(sum[x][i]==1&&sign[i]==0)
{
sign[i]=1;//标记
q[tail]=i;//入队
tail++;
}
}
head++;
}
for(i=1;i<tail;i++)
printf("%d ",q[i]);
return 0;
}
广度优先搜索一般用来求最少步数之类的
接下来,一个题目
输入
第一行输入n表示城市总数,m代表航线总数,q代表起点城市,p代表终点城市
接下来输入a,b代表a到b有一条航线
输出
最少转机次数
/*#include<stdio.h>
int sum[100][100];
int sign[100],q[100];
int n,a,b,head,tail,x;
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)sum[i][j]=0;
else sum[i][j]=100;
}
for(i=1;i<=n;i++)
{
scanf("%d %d",&a,&b);
sum[a][b]=1;
sum[b][a]=1;
}
sign[1]=1;
head=tail=1;
q[head]=1;
tail++;
while(head<tail)//队不为空时
{
x=q[head];
for(i=1;i<=n;i++)
{
if(sum[x][i]==1&&sign[i]==0)
{
sign[i]=1;//标记
q[tail]=i;//入队
tail++;
}
}
head++;
}
for(i=1;i<tail;i++)
printf("%d ",q[i]);
return 0;
}*/
#include<stdio.h>
struct node
{
int x;
int sum;
}que[100];
int main()
{
int n,m,q,p,k,y,i,j;
int sum[100][100],sign[100];
int head,tail;
scanf("%d %d %d %d",&n,&m,&q,&p);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)sum[i][j]=0;
else sum[i][j]=100;
}
for(i=1;i<=m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
sum[a][b]=1;
sum[b][a]=1;
}
head=tail=1;
que[head].x=q;
que[head].sum=0;
tail++;
sign[1]=q;
while(head<tail)
{
y=que[head].x;
for(i=1;i<=n;i++)
{
if(sum[y][i]!=100&&sign[i]==0)
{
que[tail].x=i;
que[tail].sum=que[head].sum+1;
tail++;
sign[i]=1;
}
if(que[tail].x==p)
{
k=1;
break;
}
}
if(k==1)
break;
head++;
}
printf("%d",que[tail-1].sum);
return 0;
}