我当时有疑惑的地方:
1.边数太多,采用邻接表存储,不知道怎样去重。
2.当时思路错误想着,存储下来路径,然后就不会了。
3.代码重复量太大
解答:1.不需要去重,有放在那里就好。想一想,这些重边都是有一个相同的起点和终点,假如我们先是拿的短的
来松弛,好现在松弛完了,如果在拿来另一条同起同终的边,但是权值大了,我们再去松弛,你能松弛么,明显
dis[v]<dis[u]+w,所以根本不符合判断条件,自动舍弃。同理我们先拿来同起同终的长边,再拿来短边,我们还是满足松弛条件的,自然会松弛。
3.新学习一种结构体,我们把相应的变量和函数都放在这里面,只要换一个变量名就好了。
原始加长版:
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<queue> #define INF 1e18 using namespace std; typedef long long ll; int n,m; map<string,int> flight; int cnt1,cnt2; int st,ed; ll dis1[100010],dis2[100010]; int vis[100010]; struct edge//枚举边 { int u,v; int w; }Edge[500010]; /* 这种结构超级麻烦,一会看一下,别人的代码 */ struct edge1 { int v,w; int next; }Edge1[500010]; int head1[100010]; void add_edge1(int u,int v,int w)//建立正边 { Edge1[cnt1].v=v,Edge1[cnt1].w=w; Edge1[cnt1].next=head1[u]; head1[u]=cnt1++; } struct edge2 { int v,w; int next; }Edge2[500010]; int head2[500010]; void add_edge2(int u,int v,int w)//建立反向边 { Edge2[cnt2].v=v,Edge2[cnt2].w=w; Edge2[cnt2].next=head2[u]; head2[u]=cnt2++; } void spfa1(int st) { for(int i=1;i<=n;i++) dis1[i]=INF; memset(vis,0,sizeof(vis)); dis1[st]=0;//自己距离自己是0 queue<int> q; q.push(st); vis[st]=1; while(q.size()) { int now=q.front(); q.pop(); vis[now]=0; for(int i=head1[now];i!=-1;i=Edge1[i].next) { int v=Edge1[i].v,w=Edge1[i].w; if(dis1[v]>dis1[now]+w) { dis1[v]=dis1[now]+w; if(!vis[v]) { q.push(v); vis[v]=1; } } } } } void spfa2(int ed) { for(int i=1;i<=n;i++) dis2[i]=INF; memset(vis,0,sizeof(vis)); dis2[ed]=0; queue<int> q; q.push(ed); vis[ed]=1; while(q.size()) { int now=q.front(); q.pop(); vis[now]=0; for(int i=head2[now];i!=-1;i=Edge2[i].next) { int v=Edge2[i].v,w=Edge2[i].w; if(dis2[v]>dis2[now]+w) { dis2[v]=dis2[now]+w; if(!vis[v]) { vis[v]=1; q.push(v); } } } } } int main() { while(~scanf("%d %d",&n,&m)) { cnt1=cnt2=0;//太冗长了 memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); memset(Edge,0,sizeof(Edge)); memset(Edge1,0,sizeof(Edge1)); memset(Edge2,0,sizeof(Edge2)); for(int i=0;i<=n;i++) flight.clear(); string a,b;int w; int it=1; for(int i=0;i<m;i++) { cin>>a>>b>>w; if(!flight[a])//对地名进行标号 flight[a]=it++; if(!flight[b]) flight[b]=it++; Edge[i].u=flight[a],Edge[i].v=flight[b],Edge[i].w=w;//对边进行记录 add_edge1(flight[a],flight[b],w);//添加边,利于后面的遍历 add_edge2(flight[b],flight[a],w); } cin>>a>>b; if(!flight[a]) flight[a]=it++; if(!flight[b]) flight[b]=it++; st=flight[a],ed=flight[b]; spfa1(st);//正向找到距离,也就是正向建图 spfa2(ed);//反向建图找到距离 ll ans=INF; for(int i=0;i<m;i++) { int one,two,val; one=Edge[i].u,two=Edge[i].v; val=Edge[i].w; if(dis1[one]+dis2[two]+val/2<ans) ans=dis1[one]+dis2[two]+val/2; } if(ans!=INF) printf("%I64d\n",ans); else printf("-1\n"); } return 0; } 精简版
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<queue> #define INF 1e18 using namespace std; typedef long long ll; /* 就是建立一个结构体,然后将关于他的函数,都封装在这个结构体里面, 这样的话,只需要建立一个结构体,我们就不用来重复大量的代码 */ int n,m; struct edge//枚举边 { int u,v; int w; }Edge[500010]; map<string,int> flight; int st,ed; struct s//把相关的量都封装在这个结构体里面,包括函数,才发现,她竟然还能装函数,666 { int cnt; ll dis[100010]; int vis[100010]; struct edge { int v,w; int next; }Edge[500010]; int head[100010]; void add_edge(int u,int v,int w)//建立正边 { Edge[cnt].v=v,Edge[cnt].w=w; Edge[cnt].next=head[u]; head[u]=cnt++; } void spfa(int st) { for(int i=1;i<=n;i++) dis[i]=INF; memset(vis,0,sizeof(vis)); dis[st]=0;//自己距离自己是0 queue<int> q; q.push(st); vis[st]=1; while(q.size()) { int now=q.front(); q.pop(); vis[now]=0; for(int i=head[now];i!=-1;i=Edge[i].next) { int v=Edge[i].v,w=Edge[i].w; if(dis[v]>dis[now]+w) { dis[v]=dis[now]+w; if(!vis[v]) { q.push(v); vis[v]=1; } } } } } }s1,s2; int main() { while(~scanf("%d %d",&n,&m)) { s1.cnt=s2.cnt=0; memset(Edge,0,sizeof(Edge)); memset(s1.Edge,0,sizeof(s1.Edge)),memset(s2.Edge,0,sizeof(s2.Edge)); memset(s1.head,-1,sizeof(s1.head)), memset(s2.head,-1,sizeof(s2.head)); for(int i=0;i<=n;i++) flight.clear(); string a,b;int w; int it=1; for(int i=0;i<m;i++) { cin>>a>>b>>w; if(!flight[a])//对地名进行标号 flight[a]=it++; if(!flight[b]) flight[b]=it++; Edge[i].u=flight[a],Edge[i].v=flight[b],Edge[i].w=w;//对边进行记录 s1.add_edge(flight[a],flight[b],w);//添加边,利于后面的遍历 s2.add_edge(flight[b],flight[a],w); } cin>>a>>b; if(!flight[a]) flight[a]=it++; if(!flight[b]) flight[b]=it++; st=flight[a],ed=flight[b]; s1.spfa(st);//正向找到距离,也就是正向建图 s2.spfa(ed);//反向建图找到距离 ll ans=INF; for(int i=0;i<m;i++) { int one,two,val; one=Edge[i].u,two=Edge[i].v; val=Edge[i].w; if(s1.dis[one]+s2.dis[two]+val/2<ans) ans=s1.dis[one]+s2.dis[two]+val/2; } if(ans!=INF) printf("%I64d\n",ans); else printf("-1\n"); } return 0; }
