图是由点和边组成,可分为有权图,有向图
图的存储包括了邻接矩阵和邻接表
int arr[105][105],n,m;
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
arr[a][b]=c;
}
for(int i=1;i<=n;i++){
cout<<i<<":";
for(int j=1;j<=n;j++){
if(arr[i][j]!=0){
cout<<"{"<<i<<"-->"<<j<<","<<arr[i][j]<<"}";
}
}
cout<<endl;
}
return 0;
}
floyd算法
1.速度慢
2.多源最短路径,由任意点到任意点
int arr[105][105],n,m,s;
int main(){
memset(arr,0x3F,sizeof(arr));
cin>>n>>m>>s;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
if(arr[a][b]>c){
arr[a][b]=c;
arr[b][a]=c;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
arr[j][k]=min(arr[j][k],arr[j][i]+arr[i][k]);
}
}
}
for(int i=1;i<=n;i++){
arr[i][i]=0;
if(arr[s][i]==0x3F3F3F3F){
cout<<-1<<endl;
}else{
cout<<arr[s][i]<<endl;
}
}
return 0;
}
邻接矩阵空间复杂度高
这里换用邻接表
int n,m;
struct dege{
int s,e,v;
};
int main(){
int n,m;
cin>>n>>m;
vector<vector<edge> >edg(n+5,vector<edge>());
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
edg[a].push_back((edge){b,a,c});
}
for(int i=1;i<=n;i++){
cout<<i<<":";
for(int j=0;j<edg[i].size();i++){
cout<<"{"<<i/*edg[i][j].s*/<<"-->"<<edg[i][j].e<<","<<edg[i][j].v<<"} ";
}
cout<<endl;
}
return ;
}
dijstra算法
没有负权边
struct node{
int now,dis;
bool operator<(const node&b)const{
return this->dis>b.dis;
}
};
int n,m,s,ans[100005];
struct edge{
int e,v;
};
int main(){
memset(ans,Ox3F,sizeof(ans));
cin>>n>>m>>s;
vector<vector<edge> >edg(n+5,vector<edge>());
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
edg[a].push_back((edge){b,c});
edg[b].push_back((edge){a,c});
}
priority_queue<node>que;
que.push((node){s,0});
ans[s]=0;
while(!que.empty()){
node temp=que.top();
que.pop();
if(ans[temp.now]<temp.dis){
continue;
}
for(int i=0;i<edg[temp.now].size();i++){
int e=edg[temp.now][i].e,v=edg[temp.now][i].v;
if(ans[e]>temp.dis+v){
ans[e]=temp.dis+v;
que.push((node){e,ans[e]});
}
}
}
for(int i=1;i<=n;i++){
arr[i][i]=0;
if(arr[s][i]==0x3F3F3F3F){
cout<<-1<<endl;
}else{
cout<<arr[s][i]<<endl;
}
}
return 0;
}
链式前向星结构
int n,m,head[1005];
edge edg[1005];
struct edge{
int e,v,next;
};
int main(){
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
edg[i].e=b;
edg[i].v=c;
edg[i].next=head[a];
head[a]=i;
}
for(int i=1;i<=n;i++){
cout<<i<<":";
for(int j=head[i];j!=-1;j=edg[j].next){
cout<<"{"<<i/*edg[i][j].s*/<<"-->"<<edg[j].e<<","<<edg[j].v<<"} ";
}
cout<<endl;
}
return 0;
}
Bellman-ford算法
每一轮遍历所有的边并进行更新,时间复杂度为O(n*m),可以处负权边
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct edge{
int s,e,v;
};
edge edg[200005];
int n,m,s,ans[100005],cnt;
void add_edge(int a,int b,int c){
edg[cnt].s=a;
edg[cnt].e=b;
edg[cnt].v=c;
cnt++;
}
int main(){
memset(ans,0x3F,sizeof(ans));
cin>>n>>m>>s;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
add_edge(a,b,c);
add_edge(b,a,c);
}
ans[s]=0;
for(int i=0;i<n;i++){
int f=0;
for(int j=0;j<cnt;j++){
if(ans[edg[j].e]>ans[edg[j].s]+edg[j].v){
ans[edg[j].e]=ans[edg[j].s]+edg[j].v;
}
}
if(f==0) break;
}
for(int i=1;i<=n;i++){
if(ans[i]==0x3F3F3F3F){
cout<<-1<<endl;
}else{
cout<<ans[i]<<endl;
}
}
return 0;
}
基于队列的Bellman-ford算法
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct edge{
int e,v,next;
};
edge edg[200005];
int n,m,s,ans[100005],head[100005];//head存储所有点的最后一条边的编号
int cnt,mark[100005];//mark用于每一轮的去重
void add_edge(int a,int b,int c){
edg[cnt].e=b;
edg[cnt].v=c;
edg[cnt].next=cnt++;
}
int main(){
memset(ans,0x3F,sizeof(ans));
memset(head,-1,sizeof(head));
cin>>n>>m>>s;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
add_edge(a,b,c);
add_edge(b,a,c);
}
queue<int>que;
ans[s]=0;
que.push(s);
mark[s]=1;
while(!que.empty()){
int temp=que.front();
que.pop();
mark[temp]=0;
for(int i=head[temp];i!=-1;i=edg[i].next){
int e=edg[i].e,v=edg[i].v;
if(ans[e]>ans[temp]+v){
ans[e]=ans[temp]+v;
if(mark[e]==0){
que.push(e);
mark[e]=1;
}
}
}
}
for(int i=1;i<=n;i++){
if(ans[i]==0x3F3F3F3F){
cout<<-1<<endl;
}else{
cout<<ans[i]<<endl;
}
}
return 0;
}
总结
针对不同的条件可以选择不同的最短路径算法