思路:最短路+SPFA
分析:
1 题目要求的是总的最小的花费,意思就是要求每一个人的花费都最小。
2 由于每一个人都是从1出去,最后还是都要回到1的,那么求解的时候就要分成两部分“出去+回来”;出去的话直接利用SPFA(1),1作为起点即可求出每一点的最小花费,回来的话如果是直接利用对每一个人进行SPFA,那么这样肯定超时。仔细想想要求的是每一个点到1的最小距离,那么由于给定的是一个有向图,那么只要重新建图把边反向,那么我们所求的问题就变成1到每一个点的最小距离。所以只要两步SPFA(1)即可。
3 数据类型为long long
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAXN 1000010
#define INF 0x7FFFFFFF
int t , n , m;
long long ans;
int first[MAXN] , next[MAXN];
int star[MAXN] , end[MAXN];
long long value[MAXN];
long long dis[MAXN];
long long tmp[MAXN];
int vis[MAXN];
queue<int>q;
/*初始化*/
void init(){
memset(first , -1 , sizeof(first));
memset(next , -1 , sizeof(next));
}
/*SPFA函数*/
void SPFA(int s){
memset(vis , 0 , sizeof(vis));
for(int i = 1 ; i <= n ; i++)
dis[i] = INF;
dis[s] = 0;
vis[s] = 1;
q.push(s);
while(!q.empty()){
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = first[x] ; i != -1 ; i = next[i]){
if(dis[end[i]] > dis[x] + value[i]){
dis[end[i]] = dis[x] + value[i];
if(!vis[end[i]]){
vis[end[i]] = 1;
q.push(end[i]);
}
}
}
}
}
int main(){
int a , b;
scanf("%d" , &t);
while(t--){
scanf("%d%d" , &n , &m);
/*第一次建图*/
init();
for(int i = 0 ; i < m ; i++){
scanf("%d%d%lld" , &star[i] , &end[i] , &value[i]);
next[i] = first[star[i]];
first[star[i]] = i;
}
ans = 0;
SPFA(1);
memcpy(tmp , dis , sizeof(tmp));/*把ans保存在tmp数组*/
/*第二次建图*/
init();
for(int i = 0 ; i < m ; i++){
a = star[i];
b = end[i];
star[i] = b;
end[i] = a;
next[i] = first[star[i]];
first[star[i]] = i;
}
SPFA(1);
/*求总和*/
for(int i = 2 ; i <= n ; i++)
ans += tmp[i]+dis[i];
printf("%lld\n" , ans);
}
return 0;
}