题目大意:给出n个点和m条有向边,求这n个点分别到源点的距离之和加上源点分别到这n个点的距离之和(保证每个点都可以往返源点1)
思路:很显然由于数据大小dijkstra会超时,因此这是要用到spfa(K*E)
正向存边调用spfa求的dist是源点到各个点的最短距离
反向存边调用spfa求的dist是各个点到源点的最短距离
注意输入很多,不能用cin,cout
#include<iostream>
#include<queue>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
#define int long long
const int N=1000005;
struct node
{
int to;
int w;
int next;
}edge1[N*2],edge2[N*2];//正向存的边&反向存的边
int head1[N],head2[N];//同上
int cnt;
int dist1[N];
int dist2[N];
bool vis[N];//元素是否在队内
int n,m;
void add(int u,int v,int w)
{
//正向
edge1[++cnt].to=v;
edge1[cnt].w=w;
edge1[cnt].next=head1[u];
head1[u]=cnt;
//反向存边
edge2[cnt].to=u;
edge2[cnt].w=w;
edge2[cnt].next=head2[v];
head2[v]=cnt;
}
void init1()
{
memset(dist1,0x3f3f3f3f3f,sizeof(dist1));//距离初始化到无穷
memset(vis,0,sizeof(vis));
dist1[1]=0;
}
void init2()
{
memset(dist2,0x3f3f3f3f3f,sizeof(dist2));//距离初始化到无穷
memset(vis,0,sizeof(vis));
dist2[1]=0;
}
//正向
void spfa1(int x)
{
queue<int>q;
init1();
q.push(x);//先将x入队
vis[x]=1;
while(!q.empty())
{
int tmp=q.front();
q.pop();
vis[tmp]=0;//出队 vis置0
for(int i=head1[tmp];i;i=edge1[i].next)
{
int to=edge1[i].to;
//如果能缩进距离就更新
if(dist1[to]>dist1[tmp]+edge1[i].w)
{
dist1[to]=dist1[tmp]+edge1[i].w;
//如果不在队中就入队
if(!vis[to])
{
vis[to]=1;
q.push(to);
}
}
}
}
}
//反向,代码几乎相同
void spfa2(int x)
{
queue<int>q;
init2();
q.push(x);//先将x入队
vis[x]=1;
while(!q.empty())
{
int tmp=q.front();
q.pop();
vis[tmp]=0;//出队 vis置0
for(int i=head2[tmp];i;i=edge2[i].next)
{
int to=edge2[i].to;
//如果能缩进距离就更新
if(dist2[to]>dist2[tmp]+edge2[i].w)
{
dist2[to]=dist2[tmp]+edge2[i].w;
//如果不在队中就入队
if(!vis[to])
{
vis[to]=1;
q.push(to);
}
}
}
}
}
signed main()
{
int t;
scanf("%lld",&t);
while(t--)
{
memset(head1,0,sizeof(head1));
memset(head2,0,sizeof(head2));
scanf("%lld%lld",&n,&m);
int ans=0;
for(int i=1;i<=m;i++)
{
int a,b,w;
scanf("%lld%lld%lld",&a,&b,&w);
add(a,b,w);
}
spfa1(1);
spfa2(1);
for(int i=1;i<=n;i++)
{
ans+=dist1[i];
ans+=dist2[i];
}
printf("%lld\n",ans);
}
return 0;
}