链接:QAQ
题目描述
有一个邮递员要送东西,邮局在节点 11。他总共要送 n-1n−1 样东西,其目的地分别是节点 22 到节点 nn。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 mm 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n-1n−1 样东西并且最终回到邮局最少需要的时间。
输入格式
第一行包括两个整数,nn 和 mm,表示城市的节点数量和道路数量。
第二行到第 (m+1)(m+1) 行,每行三个整数,u,v,wu,v,w,表示从 uu 到 vv 有一条通过时间为 ww 的道路。
输出格式
输出仅一行,包含一个整数,为最少需要的时间。
输入输出样例
输入 #1
5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2
输出 #1
83
说明/提示
对于 30\%30% 的数据,1 \leq n \leq 2001≤n≤200。
对于 100\%100% 的数据,1 \leq n \leq 10^31≤n≤103,1 \leq m \leq 10^51≤m≤105,1\leq u,v \leq n1≤u,v≤n,1 \leq w \leq 10^41≤w≤104,输入保证任意两点都能互相到达。
分析:这是一道最短路问题,我们首先想到了floyd,dijkstra,bellman-ford(spfa)算法,但是这道题n<=1000且路径距离皆为正整数,所以用dijkstra或bellman,这题我用了bellman。
但是我们又看到,这是有向图,而且邮递员送完货物之后还要返回,也就是说我们从一到多跑完最短路后还要从多到一跑回来,从一到多很容易,但是从多到一怎么办呢?
这时候我们想:
假设要问从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开始跑最短路,而它们的最短路是一样的。
我们把这样从多到一的最短路变式的路径反转操作称作“反向建边”。
(洛谷题解解释)
代码
#include <bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
struct node
{
int v;
int w;
node(int v,int w):v(v),w(w){}
bool operator<(const node & t)const
{
return w>t.w;
}
};
vector<node>dij[maxn];
vector<node>fdij[maxn];
int vis[maxn];
int dis[maxn];
int fdis[maxn];
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,inf,sizeof(dis));
dis[s]=0;
priority_queue<node> Q;
Q.push(node(s,dis[s]));
while(!Q.empty())
{
int u=Q.top().v; //点
Q.pop();
if(vis[u])
continue;
vis[u]=1;
for(int i=0;i<dij[u].size();i++)
{
int v=dij[u][i].v;
int w=dij[u][i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
Q.push(node(v,dis[v]));
}
}
}
}
void fdijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(fdis,inf,sizeof(fdis));
fdis[s]=0;
priority_queue<node> Q;
Q.push(node(s,fdis[s]));
while(!Q.empty())
{
int u=Q.top().v;
Q.pop();
if(vis[u])
continue;
vis[u]=1;
for(int i=0;i<fdij[u].size();i++)
{
int v=fdij[u][i].v;
int w=fdij[u][i].w;
if(fdis[v]>fdis[u]+w)
{
fdis[v]=fdis[u]+w;
Q.push(node(v,fdis[v]));
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int u,v,w;
cin>>u>>v>>w;
dij[u].push_back(node(v,w));
fdij[v].push_back(node(u,w));
}
dijkstra(1);
int ans=0;
for(int i=2;i<=n;i++)
{
ans+=dis[i];
}
fdijkstra(1);
for(int i=2;i<=n;i++)
{
ans+=fdis[i];
}
cout<<ans<<endl;
return 0;
}
也算是我迪杰斯特拉堆优化的模板233