邮递员送信
题目地址:https://www.luogu.com.cn/problem/P1629
思路:
当时就想着对每个顶点都跑一次dijkstra(时间复杂度大概是O(n^2logm)),然后愉快的超时了5个样例。
于是看了洛谷大佬们的题解:既然可以通过dijkstra求单源最短路径,那么反向建图的话可以求多源单点最短路径。
假设要问从x到1的最短路,为x->a->b->c->1,也就是说x->a,a->b,b->c,c->1都有路可走,那么我们想想,从x开始x->a,a->b,b->c,c->1的最短路不就是从1开始1->c,c->b,b->a,a->x的最短路吗?于是这时,我们把x->a,a->b,b->c,c->1这4条路径变为1->c,c->b,b->a,a->x,然后从1开始跑最短路,而它们的最短路是一样的。
大佬的反向图和原图都建立在同一个图中了。。。于是就愉快的ac了。
代码:
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N=1e3+10,M=1e5+10;
int head[2*N],ver[2*M],edge[2*M],Next[2*M],d[2*N];
bool v[2*N];
int n,m,tot,res;
typedef pair<int,int> PII;
priority_queue<PII,vector<PII>,greater<PII>> q;
void add(int x,int y,int z)
{
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
void dijkstra(int s)
{
memset(d,0x3f,sizeof(d));
memset(v,0,sizeof(v));
d[s]=0;
q.push({0,s});
while(q.size())
{
int x=q.top().second;
q.pop();
if(v[x]) continue;
v[x]=1;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i],z=edge[i];
if(d[x]+z<d[y])
{
d[y]=d[x]+z;
q.push({d[y],y});
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
add(y+n,x+n,z);
}
dijkstra(1);
for(int i=2;i<=n;i++) res+=d[i];
dijkstra(1+n);
for(int i=2+n;i<=2*n;i++) res+=d[i];
cout<<res<<endl;
return 0;
}