CCF 201712-4 行车路线

问题描述
  小明和小芳出去乡村玩,小明负责开车,小芳来导航。
  小芳将可能的道路分为大道和小道。大道比较好走,每走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 ≤ 105,1 ≤ a, b ≤ n,t是0或1,c ≤ 105。保证答案不超过106。

解析

这道题目是一道最短路径的改编,需要维护到一点的上一跳是大路的信息和到该路的最短路径信息,因为对于一个点可能由于之前走的是小路而使得到邻居节点的路径不是到该点的路径加上该点到邻居的路径,而是通过大路。所以需要多维护一个上一跳是大路的信息,以下代码使用bellman-ford,可以求得正确结果,但是会超时.
对于Dijkstra思路一样,但是只有80分就超时了。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(),m = scanner.nextInt();
        Map<Integer,List<Edge>> graph = new HashMap<>();
        for (int i = 0;i < m;i ++){
            Edge e1 = new Edge(scanner.nextInt() == 0 ,scanner.nextInt(),scanner.nextInt(),scanner.nextInt());
            List<Edge> neighbor = graph.containsKey(e1.getFrom()) ? graph.get(e1.getFrom()) : new ArrayList<>() ;
            neighbor.add(e1);
            graph.put(e1.getFrom(),neighbor);
            Edge e2 = new Edge(e1.isAvenue(),e1.getTo(),e1.getFrom(),e1.getWeight());
            neighbor = graph.containsKey(e2.getFrom()) ? graph.get(e2.getFrom()) : new ArrayList<>() ;
            neighbor.add(e2);
            graph.put(e2.getFrom(),neighbor);
        }
        /*
        dis[i][0] the last hop is avenue
        dis[i][0] the last hop is avenue
        dis[i][1] the last hop is trail
        dis[i][1] if the last hop is avenue, it is 0, otherwise ,it is the length of continuous trail
         */
        int[][] dis = new int[n+1][3];
        for(int i = 0;i <= n;i ++){
            Arrays.fill(dis[i],10000000);
        }
        dis[1][0] = dis[1][1] = dis[1][2] = 0;
        PriorityQueue<Tuple> queue = new PriorityQueue<>(new Comparator<Tuple>() {
            @Override
            public int compare(Tuple o1, Tuple o2) {
                return (int)(o1.getWeight() - o2.getWeight());
            }
        });
        queue.add(new Tuple(1,0));
        Tuple t;
        while (!queue.isEmpty()){
            t = queue.poll();
            if (t.getWeight() > Math.max(dis[t.getVertext()][0],dis[t.getVertext()][1])){
                continue;
            }
            if (!graph.containsKey(t.getVertext())){
                continue;
            }
            List<Edge> neighbors = graph.get(t.getVertext());
            for (Edge edge : neighbors){
                if (edge.isAvenue()){
                    if (dis[edge.getTo()][0] > dis[edge.getFrom()][1] + edge.getWeight())
                    {
                        dis[edge.getTo()][0] = dis[edge.getFrom()][1] + edge.getWeight();
                        if (dis[edge.getTo()][1] > dis[edge.getTo()][0]){
                            dis[edge.getTo()][1] = dis[edge.getTo()][0];
                            dis[edge.getTo()][2] = 0;
                        }
                        queue.add(new Tuple(edge.getTo(),dis[edge.getTo()][0]));
                    }

                }
                else {

                    if (dis[edge.getTo()][1] > dis[edge.getFrom()][1] - dis[edge.getFrom()][2] * dis[edge.getFrom()][2]
                            + (dis[edge.getFrom()][2] + edge.getWeight()) * (dis[edge.getFrom()][2] + edge.getWeight())){
                        dis[edge.getTo()][2] = edge.getWeight() + dis[edge.getFrom()][2];
                        dis[edge.getTo()][1] = dis[edge.getFrom()][1] - dis[edge.getFrom()][2] * dis[edge.getFrom()][2]
                                + (dis[edge.getTo()][2] * dis[edge.getTo()][2]);
                        queue.add(new Tuple(edge.getTo(),dis[edge.getTo()][1]));
                    }
                    if (dis[edge.getTo()][1] > dis[edge.getFrom()][0] + edge.getWeight() * edge.getWeight()){
                        dis[edge.getTo()][1] = dis[edge.getFrom()][0] + edge.getWeight() * edge.getWeight();
                        dis[edge.getTo()][2] = edge.getWeight();
                        queue.add(new Tuple(edge.getTo(),dis[edge.getTo()][1]));
                    }
                }
            }
        }
        System.out.println(dis[n][1]);
    }

}
class Edge{
    private int from,to,weight;
    private boolean avenue;

    public Edge( boolean avenue,int from, int to, int weight) {
        this.from = from;
        this.to = to;
        this.weight = weight;
        this.avenue = avenue;
    }

    public int getFrom() {
        return from;
    }

    public int getTo() {
        return to;
    }

    public int getWeight() {
        return weight;
    }

    public boolean isAvenue() {
        return avenue;
    }
}
class Tuple{
    private int vertex;
    public int weight;
    Tuple(int vertex,int weight){
        this.vertex = vertex;
        this.weight = weight;
    }
    public int getVertext(){
        return this.vertex;
    }
    public int getWeight(){
        return this.weight;
    }
}

Java代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Route {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(),m = scanner.nextInt();
        ArrayList<Edge> directedEdges = new ArrayList<>();
        for(int i = 0;i < m;i ++){
            directedEdges.add(new Edge(scanner.nextInt() == 0 ,scanner.nextInt(),scanner.nextInt(),scanner.nextInt()));
        }
        /*
        dis[i][0] the last hop is avenue
        dis[i][1] the last hop is trail
        dis[i][1] if the last hop is avenue, it is 0, otherwise ,it is the length of continuous trail
         */
        int[][] dis = new int[n+1][3];
        for(int i = 0;i <= n;i ++){
            Arrays.fill(dis[i],10000000);
        }
        dis[1][0] = dis[1][1] = dis[1][2] = 0;
        int temp;
        boolean flag = true;
        for(int i = 0;i < n;i ++){
            flag = true;
            for(Edge edge : directedEdges){
                /*if this edge is avenue, then can update dis[v][0] to dis[v][0]*/
                if(edge.isAvenue()){
                    dis[edge.getTo()][0] = Math.min(dis[edge.getFrom()][1] + edge.getWeight(),dis[edge.getTo()][0]);
                    if(dis[edge.getTo()][1] >= dis[edge.getTo()][0]){
                        dis[edge.getTo()][1] = dis[edge.getTo()][0];
                        dis[edge.getTo()][2] = 0;
                        flag = false;
                    }
                }
                else{
                    temp = dis[edge.getFrom()][1] - dis[edge.getFrom()][2] * dis[edge.getFrom()][2] + (dis[edge.getFrom()][2] + edge.getWeight()) * (dis[edge.getFrom()][2] + edge.getWeight());
                    if (dis[edge.getTo()][1] > temp){
                        dis[edge.getTo()][1] = temp;
                        dis[edge.getTo()][2] = dis[edge.getFrom()][2] + edge.getWeight();
                        flag = false;
                    }
                    temp = dis[edge.getFrom()][0] + edge.getWeight() * edge.getWeight();
                    if (dis[edge.getTo()][1] > temp){
                        dis[edge.getTo()][1] = temp;
                        dis[edge.getTo()][2] = edge.getWeight();
                        flag = false;
                    }
                }
            }
            if(flag){
                break;
            }
        }
        int i = 1;
        System.out.println(dis[n][1]);
    }

}

class Edge{
    private int from,to,weight;
    private boolean avenue;

    public Edge( boolean avenue,int from, int to, int weight) {
        this.from = from;
        this.to = to;
        this.weight = weight;
        this.avenue = avenue;
    }

    public int getFrom() {
        return from;
    }

    public int getTo() {
        return to;
    }

    public int getWeight() {
        return weight;
    }

    public boolean isAvenue() {
        return avenue;
    }
}

C++代码

#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    int avenue[m*4],from[m*4],to[m*4],weight[m*4];
    for(int i = 0;i < 2*m;i ++){
        scanf("%d%d%d%d",&avenue[i],&from[i],&to[i],&weight[i]);
        avenue[i+1] = avenue[i];
        from[i+1] = to[i];
        to[i+1] = from[i];
        weight[i+1] = weight[i];
        i ++;
    }
    long long dis[n+1][3];
    for(int i = 0;i <= n;i ++){
        for(int j = 0;j < 3;j ++){
            dis[i][j] = 10000000;
        }
    }
    long long temp;
    int flag = 1;
    dis[1][0] = dis[1][1] = dis[1][2] = 0;
    for(int i = 0;i < n;i ++){
        flag = 1;
            for(int j = 0;j < 2*m;j ++){
                /*if this edge is avenue, then can update dis[v][0] to dis[v][0]*/
                if(!avenue[j]){
                    dis[to[j]][0] = min(dis[from[j]][1] + weight[j],dis[to[j]][0] + 0);
                    if(dis[to[j]][1] >= dis[to[j]][0]){
                        dis[to[j]][1] = dis[to[j]][0];
                        dis[to[j]][2] = 0;
                        flag = 0;
                    }
                }
                else{
                    temp = dis[from[j]][1] - dis[from[j]][2] * dis[from[j]][2] + (dis[from[j]][2] + weight[j]) * (dis[from[j]][2] + weight[j]);
                    if (dis[to[j]][1] > temp){
                        dis[to[j]][1] = temp;
                        dis[to[j]][2] = dis[from[j]][2] + weight[j];
                        flag = 0;
                    }
                    temp = dis[from[j]][0] + weight[j] * weight[j];
                    if (dis[to[j]][1] > temp){
                        dis[to[j]][1] = temp;
                        dis[to[j]][2] = weight[j];
                        flag = 0;
                    }
                }
            }
            if(flag){
                break;
            }
    }
    printf("%lld",dis[n][1]);
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值