ccf认证2017-12-4行车路线

链接:ccf认证2017-12-4行车路线

Description

  • 小明和小芳出去乡村玩,小明负责开车,小芳来导航。
  • 小芳将可能的道路分为大道和小道。大道比较好走,每走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。
  • 现在小芳拿到了地图,请帮助她规划一个开车的路线,使得按这个路线开车小明的疲劳度最小。

    Input

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

    Output

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

    Sample Input

    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

    Sample Output

    76

    题解

  • 最短路,小路和大路分开来计算,注意中间结果可能爆int,并且可能给出重复的路,需要取最优值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,x,y) for(register int i=x;i<=y;++i)
#define repd(i,x,y) for(regsiter int i=x;i>=y;--i)
#define ll long long
using namespace std;
const int N=1e3+10;
const ll inf=1e18+7;
ll dis[N],dis0[N],n,m,in[N],g[N][N],g0[N][N];
queue<int> q;
void spfa(int s,int t){
q.push(s);
dis[s]=dis0[s]=0;
in[s]=1;
rep(i,1,n)if(i!=s)dis[i]=dis0[i]=inf;
while(!q.empty()){
int k=q.front();
q.pop();
in[k]=0;
rep(i,1,n){
ll tp=g[k][i];
if(dis[i]>dis[k]+tp){ //前一次走的大路
dis[i]=dis[k]+tp;
if(!in[i]){
q.push(i);
in[i]=1;
}
}
if(dis[i]>dis0[k]+tp){ //前一次走的小路
dis[i]=dis0[k]+tp;
if(!in[i]){
q.push(i);
in[i]=1;
}
}
if(g0[k][i]!=inf){ //现在走小路
tp=g0[k][i]*g0[k][i];
if(dis0[i]>dis[k]+tp){
dis0[i]=dis[k]+tp;
if(!in[i]){
q.push(i);
in[i]=1;
}
}
}
}
}
}

int main(){
scanf("%d%d",&n,&m);
rep(i,1,n)rep(j,i,n)g[i][j]=g[j][i]=g0[i][j]=g0[j][i]=inf;
rep(i,1,m){
int a,b,c,d;
scanf("%d%d%d%d",&d,&a,&b,&c);
if(d==0)g[a][b]=g[b][a]=min(g[a][b],(ll)c);
else g0[a][b]=g0[b][a]=min(g0[a][b],(ll)c);
}
rep(k,1,n)rep(i,1,n)rep(j,i+1,n)g0[i][j]=min(g0[i][k]+g0[k][j],g0[i][j]); //floyd先求出两点间最小的小路
spfa(1,n);
printf("%lld\n",min(dis[n],dis0[n]));
return 0;
}