关于昨天的弱化版单源最短路题,将领阶矩阵改为领接表就能过了(结尾附代码)
P1629 邮递员送信
题目描述
有一个邮递员要送东西,邮局在节点 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做应该会时间超限,于是有一种思路即将多源问题转化为单源问题,如果外面所有点回来结点1为最短,那从1到所有点的和也是这么多,相当于走反路。
代码实现就将矩阵反转过来求单源最短路,两次的和即最少总时长。
code段:
#include<stdio.h>
#include<string.h>
int main()
{
int book1[1005],book2[1005],e[1005][1005],dis[1005];
int n,m,i,j,s,ans=111483647,min,t1,t2,t3,sum=0;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)e[i][j]=0;
else e[i][j]=ans;
}
}
for(i=1;i<=m;i++){
scanf("%d %d %d",&t1,&t2,&t3);
if(e[t1][t2]>t3)e[t1][t2]=t3;
}
for(i=1;i<=n;i++)
dis[i]=e[1][i];
book1[1]=1;
for(i=1;i<=n;i++){
book1[i]=0;
book2[i]=0;
}
for(int k=1;k<=n-1;k++){
min=ans;
for(i=1;i<=n;i++){
if(book1[i]==0&&dis[i]<min){
min=dis[i];
s=i;
}
}
book1[s]=1;
for(i=1;i<=n;i++){
if(dis[i]>e[s][i]+dis[s])
dis[i]=e[s][i]+dis[s];
}}
for(i=1;i<=n;i++)sum+=dis[i];//送东西的总时间
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(j>i){
int t=e[i][j];
e[i][j]=e[j][i];
e[j][i]=t; //jiaohuan
}}}
for(i=1;i<=n;i++)
dis[i]=e[1][i];
book2[1]=1;
for(int k=1;k<=n-1;k++){
min=ans;
for(i=1;i<=n;i++){
if(book2[i]==0&&dis[i]<min){
min=dis[i];
s=i;
}
}
book2[s]=1;
for(i=1;i<=n;i++){
if(dis[i]>e[s][i]+dis[s])
dis[i]=e[s][i]+dis[s];
}}
for(i=1;i<=n;i++)sum+=dis[i];
printf("%d",sum);
}
昨天题的修正code
#include<stdio.h>
#include<string.h>
int main()
{
int book[10005],dis[10005],next[500001],first[10005];
int u[500005],v[500005],w[500005];
int n,m,i,j,s,ans=2147483647,mi,h,H;
scanf("%d %d %d",&n,&m,&s);
memset(first,-1,4*n+4);
for(i=1;i<=n;i++)
dis[i]=ans;dis[s]=0;
for(i=1;i<=m;i++){
scanf("%d %d %d",&u[i],&v[i],&w[i]);
next[i]=first[u[i]];
first[u[i]]=i;
}
int e=first[s];
while(e!=-1){
if(dis[v[e]]>w[e])
dis[v[e]]=w[e];
e=next[e];
}
book[s]=1;
for(j=1;j<=n-1;j++){
mi=ans;
for(i=1;i<=n;i++){
if(book[i]==0&&dis[i]<mi){
mi=dis[i];
h=i;
}
}
book[h]=1;
H=first[h];
while(H!=-1){
if(dis[v[H]]>dis[h]+w[H])
dis[v[H]]=dis[h]+w[H];
H=next[H];
}
}
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
}