问题描述
小明和小芳出去乡村玩,小明负责开车,小芳来导航。
小芳将可能的道路分为大道和小道。大道比较好走,每走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;
}