2.2学习总结

文章描述了一个关于邮递员在有单行道的城市中送物品的问题,需要找到送完所有物品并返回邮局的最短时间。关键在于理解道路是单向的,邮递员每次只能带一件物品。通过Dijkstra算法分别计算去程和回程的最短路径,最后累加得到总时间。文章提到了反转边的方向来处理回程路径,以及初始化和更新最短路径数组的方法。
摘要由CSDN通过智能技术生成

今天折腾了那么久又只有一个题的题解QAQ

先看看题吧

有一个邮递员要送东西,邮局在节点 11。他总共要送 �−1n−1 样东西,其目的地分别是节点 22 到节点 �n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 �m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 �−1n−1 样东西并且最终回到邮局最少需要的时间。

输入格式

第一行包括两个整数,�n 和 �m,表示城市的节点数量和道路数量。

第二行到第 (�+1)(m+1) 行,每行三个整数,�,�,�u,v,w,表示从 �u 到 �v 有一条通过时间为 �w 的道路。

输出格式

输出仅一行,包含一个整数,为最少需要的时间。

输入输出样例

输入 #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≤�≤2001≤n≤200。

对于 100%100% 的数据,1≤�≤1031≤n≤103,1≤�≤1051≤m≤105,1≤�,�≤�1≤u,v≤n,1≤�≤1041≤w≤104,输入保证任意两点都能互相到达。

刚开始看题的时候真的感觉好开心,这和上面那个题目没啥区别,我正开开心心的把上一题的代码打上去一输入数据发现算不出来83哈哈,仔细一看题发现还要返回来回来我想就乘个二吧,但是手算发现还是到不了八十三,这时候我才开始认真对待这个题目,实在想不明白,难道是回来的时候和去的路线不太一样?就很迷茫,迷茫时该怎么办这时候就要画图了::

 简单画了一个图是这样,然后我就在去看了一下题解,才顿时明白,举个例子在这主要是理解题目的这段话:

由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 �m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局

是我想复杂了,本来我以为回来的时候箭头翻转,然后最短的就是按原路返回,简直是大错特错,路当然不会因为一个邮递员的通过而去变化它的通行方向,而这里我们之所以要将这些进行翻转是为了将多元化的问题单元化,全部都转化为一到各个点的最短路径。

#include<stdio.h>

int a[1005][1005],dis[1005],i,j;
#define INF 1e9;
void init(int n)
{
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            if(i!=j)
            a[i][j]=INF;//i==j就为零否则则为无穷大
        }
    }
}
void dij(int n)//经典的单元最短路径代码
{
    int f[1005]={0};
    f[1]=1;
    int v;
    for(i=1;i<n;i++)
    {
        int min=INF;
        for(j=1;j<=n;j++)
        {
            if(!f[j]&&min>dis[j])
            {
                min=dis[j];
                v=j;
            }
        }
        f[v]=1;
        for(j=1;j<=n;j++)
        {
            if(!f[j]&&a[v][j]+dis[v]<dis[j])
            {
                dis[j]=a[v][j]+dis[v];
            }
        }
    }
}
void fan(int n)
{
    for(i=1;i<=n;i++)
    {
        for(j=i+1;j<=n;j++)//反转,也就是将所以箭头的方向调转,方便将回来时各个点到一的最短路径转化为一到各个点的最短路径;
        {
            int t=0;
            t=a[i][j];
            a[i][j]=a[j][i];
            a[j][i]=t;
        }
    }
}
int minn(int x,int y)
{
    return (x>y)?y:x;
}
int main()
{
    int n,m,x,y,z;
    scanf("%d %d",&n,&m);
    init(n);
    for(i=1;i<=m;i++)
    {
        scanf("%d %d %d",&x,&y,&z);
        a[x][y]=minn(a[x][y],z);//注意这里忒重要了,可以保证多次输入的相同起终点里取最短路。
    }
    for(i=1;i<=n;i++)
    {
        dis[i]=a[1][i];
    }
    dij(n);
    int ans;
    for(i=1;i<=n;i++)
    {
        ans+=dis[i];
    }
    fan(n);
    for(i=1;i<=n;i++)
    {
        dis[i]=a[1][i];//刚开始我一直没明白为什么只变一个,其实这里它是后来会全部都更新一遍的,不重新初始化也没关系。
    }
    dij(n);
    for(i=1;i<=n;i++)
    {
        ans+=dis[i];
    }
   printf("%d\n",ans);
    return 0;
}

首先这还是一个最短路径的题,所以我们可以将最短路径的有关代码准备好,并编制一个函数。

小结:这个题目的总体思想就是求两遍最短路径,运用反转将回来时也变成单源最短路。这里由于一定会有到某个点的路所以对dis没有很大的要求,但是有些题目里面可能是不会有路到某点的,这时候就要设置足够大的dis来装inf无穷大了。

有些人或许生来就有翅膀,也有些人选择靠自己的力量飞翔,有些人失败后就永远趴伏在泥泞里,也有些人,就算历经波折,也要翱翔在蓝天之上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值