【大渣】图的存储方法

图论 这里以NKOJ 1120为例

Description

有一无负权有向图。求指定两点间的最短路径。 

Input

输入:第一行,两个数字n和m,表示n个顶点,m条边 
接下来的m行,每行三个整数,分别表示边的起点、终点和边的长度 
最后一行 两个整数 x y 表示求从点x到点y的最短路径 

Output

输出:一行,一个整数,最短路径长度 

Sample Input

3  3
1  2  5
1  3  2
3  2  1
1  2

Sample Output

3

Hint

注:所有数据都不超过100 

//最短路算法均为SPFA

====================================================================================================================================

第一种 也就是最粗暴的 邻接矩阵存图

不多解释,这个应该都懂

#include<cstdio>
int n,m,a,y,z;
int map[105][105];
int q[405],dis[105]; 
void SPFA(int s)                            
{        
        bool f[105];    
		int i,head=1,tail=2,x;
        for(i=1;i<=n;i++){dis[i]=99999999;f[i]=false;} //SPFA初始化 
        q[1]=s;f[s]=true;dis[s]=0;       
        while(head!=tail)
        {
             x=q[head++];  
			 f[x]=false;     
             for(i=1;i<=n;i++)                
                 if (dis[x]+map[x][i]<dis[i])              
                 {
                        dis[i]=dis[x]+map[x][i];
                        if (f[i]==false)                                                 
                        {
                         q[tail++]=i;    
						 f[i]=true;
                        }
                 }
        }
}
int main()
{
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)//初始化Map数组 
	  for(j=1;j<=n;j++)
	   if(i!=j)map[i][j]=99999999;
	   
      
	for(int i=1;i<=m;i++)
	 {
	  scanf("%d%d%d",&a,&y,&z);
	  map[a][y]=z;
     }
     scanf("%d%d",&a,&z);
     SPFA(a);
     printf("%d",dis[z]);
     return 0;
}
====================================================================================================================================

第二种 临接链表 其实就是多开个V数组来记录每个点的连接情况 v[x][0]表示连接点的个数 后面表示对应的点的编号

#include<cstdio>
#define maxn 105
#define inf 1<<25
int n,m,j,i,x,y,z;
int v[maxn][maxn],Map[maxn][maxn];
int q[maxn*4],dis[maxn];
bool f[maxn];
void _spfa(int s)
{
	int i,x,head=1,tail=2;
	for(i=1;i<=n;i++)
	  {
	    f[i]=false;
	    dis[i]=inf;
      }
	dis[s]=0;q[1]=s;f[s]=true;
	
	while(head!=tail)
	{
		x=q[head++];
		f[x]=false;
		
		for(i=1;i<=v[x][0];i++)//v[x][0]表示连接的点的个数 能提前结束循环 
		{
		  if(dis[x]+Map[x][v[x][i]]<dis[v[x][i]])
		    {
			   dis[v[x][i]]=dis[x]+Map[x][v[x][i]];
		       if(f[v[x][i]]==false)
		       {
		     	f[v[x][i]]=true;
		     	q[tail++]=v[x][i];
		       }
		    }
		}
		
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	 for(j=1;j<=n;j++)
	 if(i!=j)Map[i][j]=inf;

	for(i=1;i<=m;i++)//存入点 
	{
		scanf("%d%d%d",&x,&y,&z);
		v[x][0]++;//连接的点的个数 
		v[x][v[x][0]]=y;//记录其对应的编号 
		Map[x][y]=z;
	}
	scanf("%d%d",&x,&y);
	_spfa(x);
	printf("%d",dis[y]);
	return 0;
}

====================================================================================================================================

第三种 边存储 可节省大量空间 效率也比较高

//end[i]记录第i条边的重点,len[i]记录第i条边的长度 ,next[i]表示跟第i条边有相同起点的上一条边的编号,last[x]表示以x为起点的边最新一条的边的编号。

#include<cstdio>
#define maxn 105
#define inf 1<<25
int dis[maxn],len[maxn],end[maxn],next[maxn],last[maxn];
int q[maxn*4];
bool f[maxn];
int n,m,x,y,z;
void _spfa(int s)
{
	int i,x,head=1,tail=2;
	for(i=1;i<=n;i++)
	{
		dis[i]=inf;
		f[i]=false;
	}
	dis[s]=0;f[s]=true;q[1]=s;
	while(head!=tail)
	{
		x=q[head++];
		f[x]=false;
		int k=last[x];
		while(k)//以x为起点,k为终点讨论
		{
			int t=end[k];
			if(dis[t]>dis[x]+len[k])
			{
				dis[t]=dis[x]+len[k];
				if(!f[t])
				{
					f[t]=1;
					q[tail++]=t;
				}
			}
			k=next[k];//不要忘记更新k的值
		}
	}
}
int main()
{
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		end[i]=y;
		len[i]=z;
		next[i]=last[x];
		last[x]=i;
	}
	scanf("%d%d",&x,&y);
	_spfa(x);
	printf("%d",dis[y]);
	return 0;
}

嗯 存图大概就是这三种 最后一种比较难理解 不过多写即便就好了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值