CCF 2017-12-4 行车路线(最短路变形)

本文介绍了一种解决路径规划问题的算法,旨在找到从起点到终点使驾驶员疲劳度最小的路线。考虑到不同类型的路段(大道和小道)对疲劳度的影响,通过Floyd预处理和SPFA算法实现最优路径的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    小明和小芳出去乡村玩,小明负责开车,小芳来导航。 
  小芳将可能的道路分为大道和小道。大道比较好走,每走1公里小明会增加1的疲劳度。小道不好走,如果连续走小道,小明的疲劳值会快速增加,连续走s公里小明会增加s2的疲劳度。 
  例如:有5个路口,1号路口到2号路口为小道,2号路口到3号路口为小道,3号路口到4号路口为大道,4号路口到5号路口为小道,相邻路口之间的距离都是2公里。如果小明从1号路口到5号路口,则总疲劳值为(2+2)2+2+22=16+2+4=22。 
  现在小芳拿到了地图,请帮助她规划一个开车的路线,使得按这个路线开车小明的疲劳度最小。

输入格式

  输入的第一行包含两个整数n, m,分别表示路口的数量和道路的数量。路口由1至n编号,小明需要开车从1号路口到n号路口。 
  接下来m行描述道路,每行包含四个整数t, a, b, c,表示一条类型为t,连接a与b两个路口,长度为c公里的双向道路。其中t为0表示大道,t为1表示小道。保证1号路口和n号路口是连通的。

输出格式

  输出一个整数,表示最优路线下小明的疲劳度。

样例输入

6 7 
1 1 2 3 
1 2 3 2 
0 1 3 30 
0 3 4 20 
0 4 5 30 
1 3 5 6 
1 5 6 1

样例输出

76

样例说明

  从1走小道到2,再走小道到3,疲劳度为52=25;然后从3走大道经过4到达5,疲劳度为20+30=50;最后从5走小道到6,疲劳度为1。总共为76。

数据规模和约定

  对于30%的评测用例,1 ≤ n ≤ 8,1 ≤ m ≤ 10; 
  对于另外20%的评测用例,不存在小道; 
  对于另外20%的评测用例,所有的小道不相交; 
  对于所有评测用例,1 ≤ n ≤ 500,1 ≤ m ≤ 1e5,1 ≤ a, b ≤ n,t是0或1,c ≤ 1e5。保证答案不超过1e6。

 

思路:

floyed预先处理小路情况

dis[i]记录的是1到i的以大路结束的最小权值,dis1[i]记录的是以小路结束的最小权值

spfa

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;

typedef long long ll;
ll g[505][505],g1[505][505],dis[505],dis1[505];
int vis[505];
int t,a,b;
ll v;
int n,m;
void floyd()
{
    for(int i=1; i<=n; i++)
    {
        for(int j=i+1; j<=n; j++)
        {
            for(int k=1; k<=n; k++)
            {
                if(k==i||k==j)
                    continue;
                if(g1[i][j]>g1[i][k]+g1[k][j])
                    g1[i][j]=g1[j][i]=g1[i][k]+g1[k][j];
            }
        }
    }
}
void spfa(int s)
{
    queue<int>que;
    dis[s]=0;
    dis1[s]=0;
    vis[s]=1;
    que.push(s);
    while(!que.empty())
    {
        ll tmp=que.front();
        que.pop();
        vis[tmp]=0;
        for(int i=1; i<=n; i++)
        {
            if(dis[i]>dis1[tmp]+g[tmp][i]&&g1[tmp][i]<INF)///小加大
            {
                dis[i]=dis1[tmp]+g[tmp][i];
                if(!vis[i])
                {
                    vis[i]=1;
                    que.push(i);
                }
            }
            if(dis[i]>dis[tmp]+g[tmp][i]&&g[tmp][i]<INF)///大加大
            {
                dis[i]=dis[tmp]+g[tmp][i];
                if(!vis[i])
                {
                    vis[i]=1;
                    que.push(i);
                }
            }
            if(dis1[i]>dis[tmp]+g1[tmp][i]*g1[tmp][i]&&g1[tmp][i]<INF)
            {
                dis1[i]=dis[tmp]+g1[tmp][i]*g1[tmp][i];
                if(!vis[i])
                {
                    vis[i]=1;
                    que.push(i);
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(dis,INF,sizeof(dis));
    memset(dis1,INF,sizeof(dis1));
    memset(vis,0,sizeof(vis));
    memset(g,INF,sizeof(g));
    memset(g1,INF,sizeof(g1));
    while(m--)
    {
        scanf("%d%d%d%lld",&t,&a,&b,&v);
        if(t==1&&v<g1[a][b])
            g1[a][b]=g1[b][a]=v;
        if(t==0&&v<g[a][b])
            g[a][b]=g[b][a]=v;
    }
    floyd();
    spfa(1);
    printf("%d\n",min(dis[n],dis1[n]));
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值