2M. Choose the best route

这篇博客探讨了如何处理多起点单终点的有向图最短路径问题,通过使用反向图将问题转换为单起点多终点问题,从而避免Dijkstra算法的超时。作者指出,在输入路线数据时要注意起点和终点的反向,并给出了详细的代码实现。代码中展示了如何利用反向图进行松弛操作和最短路径计算,以提高效率。
摘要由CSDN通过智能技术生成

#include<bits/stdc++.h>
using namespace std;
int dp[1005],V[1005];
int MAP[1005][1005];
const int inf=0x3f3f3f3f;
int minhh(int x,int y)
{
    if(x<=y)return x;
    else return y;
}
int main() 
{    
    int i,n,m,s,min,a,b,w[1005];
    while(scanf("%d %d %d",&n,&m,&s)!=EOF)
    {    
        memset(MAP,inf,sizeof(MAP));
        for(i=1;i<=n;i++)MAP[i][i]=0;
        while(m--)
        {
            scanf("%d %d %d",&a,&b,&i);
            MAP[b][a]=minhh(MAP[b][a],i);
            //MAP[b][a]=MAP[a][b];

//注意这里是本题是有向图,所以利用反向图思路是,输入数据路线的起点和终点也要反向
        }
        scanf("%d",w);
        for(i=1;i<=w[0];i++)scanf("%d",&w[i]);
        //录入题给信息
            memset(dp,inf,sizeof(dp));
            memset(V,-1,sizeof(V));
            for(i=1;i<=n;i++)dp[i]=MAP[s][i];//反向图,起点当终点,终点当起点,变为单源多终点问题 
            while(1)
            {
                dp[1003]=inf;min=1003;m=0;//初始化 
                for(i=1;i<=n;i++)
                {
                    if(V[i]==-1&&dp[i]<dp[min])min=i;
                }//找出最小边
                for(a=1;a<=w[0];a++)if(min==w[a]){m=-1;break;}
                if(m==-1)break;
                if(min==1003)break;//所有路径都考虑完了 
                V[min]=0;//表示这个城市考虑过了
                for(i=1;i<=n;i++)
                {
                    if(V[i]==-1&&dp[i]>dp[min]+MAP[min][i])
                    dp[i]=dp[min]+MAP[min][i];
                }//松弛操作,更新到达每个城市的最短路径
            }
        
        if(dp[min]>=inf)printf("-1\n");
        else printf("%d\n",dp[min]);
    }
        
    return 0;
}
总结 :

1.这题是多起点单个终点的有向图,直接DJ会超时,可以使用反向图(起点当终点,终点当起点,变成单起点多终点问题)或者自己再加上一个到各个起点距离都为0的新起点,变成单起点单终点问题,以此简化运算,提高效率

2.对于有向图用反向图思路解题时,要注意输入路线数据时的起点和终点也要反向

直接多起点硬解案例(会超时)

#include<bits/stdc++.h>
using namespace std;
int dp[1005],V[1005];
int MAP[1005][1005];
const int inf=0x3f3f3f3f;
int minhh(int x,int y)
{
    if(x<=y)return x;
    else return y;
}
int main() 
{    
    int i,n,m,s,min,minn,a,b,w[1005];
    while(scanf("%d %d %d",&n,&m,&s)!=EOF)
    {    
        memset(MAP,inf,sizeof(MAP));
        for(i=1;i<=n;i++)MAP[i][i]=0;
        while(m--)
        {
            scanf("%d %d %d",&a,&b,&i);
            MAP[a][b]=minhh(MAP[a][b],i);
            //MAP[b][a]=MAP[a][b];
        }
        scanf("%d",w);
        for(i=1;i<=w[0];i++)scanf("%d",&w[i]);
        //录入题给信息
        minn=inf;
        for(a=1;a<=w[0];a++)
        {
            memset(dp,inf,sizeof(dp));
            memset(V,-1,sizeof(V));
            for(i=1;i<=n;i++)dp[i]=MAP[w[a]][i];
            while(1)
            {
                dp[1003]=inf;min=1003;m=0;//初始化 
                for(i=1;i<=n;i++)
                {
                    if(V[i]==-1&&dp[i]<dp[min])min=i;
                }//找出最小边 
                if(min==s)break;
                if(min==1003)break;//所有路径都考虑完了 
                V[min]=0;//表示这个城市考虑过了
                for(i=1;i<=n;i++)
                {
                    if(V[i]==-1&&dp[i]>dp[min]+MAP[min][i])
                    dp[i]=dp[min]+MAP[min][i];
                }//松弛操作,更新到达每个城市的最短路径
            }
            minn=minhh(dp[min],minn);
        }//考虑不同起点的最短路径,找出最小的 
        if(minn>=inf)printf("-1\n");
        else printf("%d\n",minn);
    }
        
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值