题意: 有一群人, 要去公交车站坐车,每个人要去的地方一共有N个点,然后有M条路线,要你计算一下从第一个点到所有点后,在从所有点返回第一个点的最小花费。(公交车不能返回,也就是有向图构图)
思路:
先正向跑一边SPFA , 然后反向构图在跑一遍SPFA即可
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<queue>
using namespace std;
#define LL long long
int n , m ;
const int maxn = 1000000 + 100 ;
int head[maxn] ;
int cnt = 0 ;
LL dis[maxn] ;
LL ans ;
int vis[maxn] ;
int x[maxn] , y[maxn] ; LL z[maxn] ;
struct Edge{
int next , to ;
LL val ;
}st[maxn];
void init(){
cnt = 0 ;
memset(head , -1 , sizeof(head)) ;
memset(dis , 0x3f , sizeof(dis)) ;
memset(vis , 0 , sizeof(vis)) ;
}
void add(int u , int v , LL w ){
st[cnt].next = head[u] ;
st[cnt].to = v ;
st[cnt].val = w ;
head[u] = cnt++ ;
}
void SPFA(int s){
dis[s] = 0 ;
queue<int> q ;
q.push(s) ;
while(!q.empty()){
int u = q.front() ;
q.pop() ;
vis[u] = 0 ;
for(int i = head[u] ; i != -1 ; i = st[i].next){
LL cost = st[i].val ;
int v = st[i].to ;
if(dis[v] > dis[u] + cost ){
dis[v] = dis[u] + cost ;
if(!vis[v]){
vis[v] = 1 ;
q.push(v) ;
}
}
}
}
}
void Addsum(){
for(int i = 1 ; i <= n ; i++){
ans += dis[i] ;
}
}
int main(){
int t ;
cin >> t ;
while(t--){
ans = 0 ;
scanf("%d %d", &n,&m ) ;
init() ;
int u , v ; LL w ;
for(int i = 0 ; i < m ; i++){
scanf("%d %d %lld",&u,&v,&w) ;
y[i] = u ; x[i] = v ;
z[i] = w ;
add(u , v , w) ;
}
SPFA(1) ;
Addsum() ;
init() ;
for(int i = 0 ; i < m ; i++) add(x[i] , y[i] , z[i] ) ;
SPFA(1) ;
Addsum() ;
cout << ans << endl ;
}
return 0 ;
}