注意:在图论问题中,当节点个数多于1000个时用邻接表或者前向星,其中,前向星最快。当节点个数小于1000个时,用邻接矩阵,好写。PAT中点的个数一般不多,在竞赛中有几万个顶点时,必须用前向星。
题目:PAT 1030
https://pintia.cn/problem-sets/994805342720868352/problems/994805464397627392
题意:在无向图中,输出最小花费的最短路径(多条件)及最小花费。
题解:
#include<bits/stdc++.h>
using namespace std;
const int MAXV=510;
const int INF=1000000000;
int n,m,st,ed,G[MAXV][MAXV],cost[MAXV][MAXV];//G是邻接矩阵存储距离,cost存储花费
int d[MAXV],c[MAXV],pre[MAXV];
//d存储起点到某点的最短路径,c存储起点到某点的最小花费,pre存储某点的前一个节点
int vis[MAXV]={false};//标记某点是否被访问过
void Dijkstra(int s)//s是传入的起点
{
fill(d,d+MAXV,INF);//fill对一维数组的赋值与二维数组不同
fill(c,c+MAXV,INF);//c数组也要进行比较,且要赋值为最大值,因为在下面的松弛时,要取小的
for(int i=0;i<n;i++) pre[i]=i;//路径数组初始化
d[s]=0;c[s]=0;//重要初始化
for(int i=0;i<n;i++)
{int u=-1,MIN=INF;//重要初始化
for(int j=0;j<n;j++)
{
if(vis[j]==false&&d[j]<MIN)
{
u=j;MIN=d[j];
}
}//找到路径最优化的未访问的点
if(u==-1)return;//连通图中不存在未访问的点
vis[u]=true;//标记访问
for(int v=0;v<n;v++)
{
if(vis[v]==false&&G[u][v]!=INF)
{//未访问且路径存在
if(d[v]>d[u]+G[u][v])
{//更新
d[v]=d[u]+G[u][v];
c[v]=c[u]+cost[u][v];
pre[v]=u;//更新路径
}
else if(d[v]==d[u]+G[u][v])
{
if(c[v]>c[u]+cost[u][v])
{
c[v]=c[u]+cost[u][v];
pre[v]=u;
}
}
}
}
}
}
void DFS(int v)
{
if(v==st)
{//设置递归的返回条件
cout<<st<<' ';return;
}
DFS(pre[v]);
cout<<v<<' ';
}
int main()
{
int u,v;
cin>>n>>m>>st>>ed;
fill(G[0],G[0]+MAXV*MAXV,INF);//cost数组不必初始化
for(int i=0;i<m;i++)
{
cin>>u>>v;
cin>>G[u][v];
cin>>cost[u][v];
G[v][u]=G[u][v];
cost[v][u]=cost[u][v];//无向图
}
Dijkstra(st);
DFS(ed);//打印路径,注意是输入终点进行打印
cout<<d[ed]<<' '<<c[ed]<<endl;
return 0;
}