CSP 行车路线 最短路变型

问题描述:

  • 小明和小芳出去乡村玩,小明负责开车,小芳来导航。
  • 小芳将可能的道路分为大道和小道。大道比较好走,每走1公里小明会增加1的疲劳度。小道不好走,如果连续走小道,小明的疲劳值会快速增加,连续走s公里小明会增加s*s的疲劳度。
  • 例如:有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 ≤ 105。保证答案不超过1e6。

分析:

  • 典型的最短路问题,容易想到:如果没有小路,那么这题就是最基础的最短路,直接用dijkstra求解,可以通过60%的数据
  • 题目中并没有说明是否存在重边 10%的数据
  • 小路增加的疲劳度计算是连续走小路的路长的平方,因此在多段图中,就不能像简单的最短路问题一样直接存储节点的编号和到这个点的最短路径长度
  • 根据题目描述,在dijkstra的过程中,每个节点都记录 到该节点的前一段走小路的长度s、走小路前的疲劳值、走到这点的总疲劳值
  • 设置从节点1到节点i的最小疲劳值为dist1[i] - 最后一段是大路;dist2[i] - 最后一段是小路
  • 根据当前节点到下一节点路径类别,计算产生的总疲劳值,根据情况入队(优先队列实现的dijkstra)
  • 注意:c<=1e5, 计算过程中可能会出现 c*c 这种计算,使用int会爆int , 把整型全部设为long long 20%的数据
  • 别问我为什么知道那些百分比,说出来都是泪

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 1e9+10;
const LL maxn = 505;
typedef pair<LL,LL> P;

vector<P>mp[maxn][maxn];
LL dist1[maxn],dist2[maxn],vis1[maxn],vis2[maxn];
LL n,m,t,a,b,c;
struct node
{
    LL id,totCost,daCost,xiaoCost,s;
    node(){}
    node(LL a,LL b,LL c) {id=a;totCost=b;s=c;}
    node(LL a,LL b,LL c,LL d){id=a;totCost=b;s=c;daCost = d;}
    friend bool operator<(const node& a,const node& b)
    {
        if(a.totCost!=b.totCost)return a.totCost>b.totCost;
        return a.s>b.s;
    }
};

priority_queue<node>priq;

void init()
{
    while(!priq.empty()) priq.pop();
    for(LL i=0;i<maxn;i++)
    {
        dist1[i] = dist2[i] = INF;
        vis1[i] = vis2[i]= 0;
    }

    for(LL i=0;i<maxn;i++)
        for(LL j=0;j<maxn;j++)
            mp[i][j].clear();

}

void input()
{
    cin>>n>>m;
    while(m--)
    {
        cin>>t>>a>>b>>c;
        mp[a][b].push_back(P(t,c));
        mp[b][a].push_back(P(t,c));
    }
}

void dijkstra()
{
    dist1[1] = dist2[1] = 0;
    vis2[1]=1;
    priq.push(node(1,0,0,0));
    while(!priq.empty())
    {
        node e = priq.top();
        priq.pop();
        LL now=e.id;
        LL totCost = e.totCost;
        LL daCost = e.daCost;
        LL s = e.s;
        if(s) vis2[now]=1;
        else vis1[now]=1;
        for(LL i=2;i<=n;i++)
        {
            if(vis1[i]&&vis2[i]) continue;

            for(LL j=0;j<mp[now][i].size();j++)
            {
                P xxx = mp[now][i][j];

                if(xxx.first){   // 这条路是小路
                    LL len =  s+xxx.second;
                    LL cost = daCost +len*len;    ///watch out!!    len*len>int
                    if(cost<=dist2[i]) {
                        dist2[i] = cost;
                        priq.push(node(i,cost,len,daCost));
                    }

                }else {                     // 这条路是大路
                    LL cost = totCost + xxx.second;
                    if(cost<=dist1[i]){
                        dist1[i] = cost;
                        priq.push(node(i,cost,0,cost));
                    }
                }
            }
        }
    }
}


int main()
{
    init();
    input();
    dijkstra();
    cout<<min(dist1[n],dist2[n])<<endl;
    return 0;
}

posted @ 2018-09-10 22:58  小螺号打豆豆  阅读(1073)  评论(0编辑  收藏  举报