思路:先求邮局到每个点的最短距离,即多源最短路径,接着反过来算每个点到邮局的距离,变成了多源单终点的最短路径,很明显是非常费时,这里可以得60分,但我们想一想有什么可以将它转边为转化多源最短路径,建议想想再看答案。
答案是:将每条边反过来存,那么此时算得的邮局到剩余每个点的距离,就是原图每个点到邮局的距离,为了方便,反过来的图还是存在链式前项星中,只不过每个点加N,那么邮局就是N+1那个点。
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
int n,m,s,dis[2507],head[2507],cnt;
bool vis[2507];
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}//快读
struct Edge{
int u,v,w,next;
}e[300007];//链式前项星存图
struct node{
int w,now;
inline bool operator <(const node &x)const{
return w>x.w;
}//自定义排序
};
priority_queue<node>q;
void add(int u,int v,int w){
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}//链式前项星存边
void Dijkstra(int start){
memset(dis,0x3f3f3f3f,sizeof(dis));
dis[start]=0;
q.push((node){0,start});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
q.push((node){dis[v],v});
}
}
}
}
int main(){
long long sum=0;
n=read(),m=read();
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
add(x,y,z);
add(y+n,x+n,z);//键反边
}
Dijkstra(1);
for(int i=2;i<=n;i++)sum+=dis[i];//正边先加
memset(vis,0,sizeof(vis));
Dijkstra(n+1);
for(int i=n+2,len=2*n;i<=len;i++){//反边再加
sum+=dis[i];
}
cout<<sum;
return 0;
}