FZU-2298 Traffic jam(交通堵塞) (最短路)

Xzz is a child with severe procrastinations. The new semester begins, He still has a lot of homework to do. Now, he needs your help. As the best friend, you are good at math. So, you will help him do some math homework. Now Xzz wants to go to your home. You can regard the traffic network as a undirected graph with n nodes (numbered from 1 to n) and m edges.

小渣渣(Xzz)是一个重度拖延症患者。新学期开始了,但他还有一堆作业要做。现在,他需要你的帮助。作为他最好的朋友,你相当擅长数学。所以,你得帮助他做点数学作业。现在小渣渣想去你家。你可以认为交通网络是一张n个节点(1-n标号),m条边的无向图

Xzz’s home at node s, and your at node t. At each node i, there is a traffic light, and the traffic light change the status after ai, which means that you can only leave node i, at time[0, ai), [2 * ai, 3 * ai), [4 * ai, 5 * ai), … , [2k * ai, (2 * k + 1) * ai). If ai = 0 means there is no traffic light, you can leave at any time. And there are m edges, each edge means it will take Xzz vi time from node xi to node yi. Now Xzz wants to know how much time he will take to arrive your home. 

小渣渣的家在节点s,你家在节点t,在每个节点i,都有一个信号灯,以及这个信号灯会在ai时间后变更状态,这意味着你只能在[0, ai), [2 * ai, 3 * ai), [4 * ai, 5 * ai), … , [2k * ai, (2 * k + 1) * ai)这些时间段内离开这里。如果ai=0,那么意味着这个地方没有信号灯,你随时可以离开。有m条边,每条边的vi都意味着小渣渣从xi到yi(线段两端点)要花vi的时间,现在小渣渣想知道他到你家要花多久时间。

Input

First line of the input file contains an integer T(0 < ≤ 20) that indicates how many cases of inputs are there.

第一行的输入包含一个整数T,这代表着有多少组输入样例。

The description of each case is given below:

每一行的输入描述如同给定的下文所述:

The first line of each case contains two numbers n, m, means there are n nodes and m edges.

每个样例的第一行包含两个数字n,m,意味着有n个节点(路口)和m条边(路)

(n ≤ 1000, m ≤ n(n-1) / 2)

Then follow n lines. In ith line there will be a number, ai.(ai ≤ 1000)

接下来有n行。在第i行内有一个数字ai

Then follow m lines. In ith line there will be three numbers, xi, yi and vi, means there is a edge between xi and yi, and Xzz take vi time to go trough this edge. vi ≤ 1000.

接下来有m行。在第i行有三个数xi,yi,vi,意味着xi,yi两点间存在一条边,小渣渣花vi的时间通过这条边。

The last line contains two numbers s, t. It’s guarantee that there is at least one path between node s and t.

最后一行包含两个正数s,t。数据保证s与t之间存在至少一条边。

Output

One integer means the minimum time Xzz go to node t.

输出一个整数,代表着小渣渣去节点t的最少时间。

Sample Input

1
9 14
3
5
7
3
5
7
9
3
5
1 2 4
1 8 8
2 3 8
2 8 11
3 4 7
3 6 4
3 9 2
4 5 9
4 6 14
5 6 10
6 7 2
7 9 6
7 8 1
8 9 7
1 5

Sample Output

28

最小时间?节点,边?无向图?自然是要用dijkstra/spfa/floyd安排一波了,这里使用了优先队列优化的dijkstra,不过有一点不同的是,在节点处要根据当前累计时间t(i)的不同加上相应区间的时间增量(就是需不需要等红绿灯)

所以有如下思路:

  1. 一如既往的链式前向星建图,注意:无向图需要对xi,yi和yi,xi分别建立一条边,所以数组需要开得更大(至少极限数据的两倍)。
  2. 建立优先队列,以及遍历图内需要的结构体(或者一个变量也行),重载优先队列的<(或>)运算符。
  3. 在到达某个节点时(从queue_name.top()那里接收的当前位置),以当前累积的时间除以当前节点的ai,这个整商对2取余(题目中的奇数倍区间需要等红绿灯),判断当前时间状态是否需要再加等红绿灯时间,以下按照套路来即可

(数据较大,建议使用scanf,或者解除同步的cin) 

代码如下:

#include <iostream>
#include <cstdio>
//#include <bits/stdc++.h>
#include <queue>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define printlnlld(a) printf("%lld\n",a)
#define printlnd(a) printf("%d\n",a)
#define printlld(a) printf("%lld",a)
#define printd(a) printf("%d",a)
#define reset(a,b) memset(a,b,sizeof(a))
const int INF=0x3f3f3f3f;
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod=1000000007;
///Schlacht von Stalingrad
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
int trafic_lights[5605],tim[5605];
bool vis[5605];
int heads[2006020];
struct node
{
    int toward,next,value;
} nodes[2006020];
struct info
{
    int current;
    int curtim;
};
int cnt;
void construction(int from,int to,int value)
{
    node a= {to,heads[from],value};
    nodes[cnt]=a;
    heads[from]=cnt++;
}
void initialization()//多组数据必要的初始化
{
    reset(heads,-1);
    reset(trafic_lights,0);
    reset(tim,0x3f);
    reset(vis,false);
    cnt=0;
}
bool operator<(info a,info b)//由于优先队列会自动排序,但默认的运算符不认识结构体类型,所以需要重载运算符
{
    return a.curtim>b.curtim;
}
void dijkstra(int start,int destination)
{
    priority_queue<info>pq;
    info a= {start,0};
    pq.push(a);
    vis[start]=true;
    tim[start]=0;
    while(!pq.empty())
    {
        info current=pq.top();
        pq.pop();
        if(tim[current.current]!=current.curtim)
            continue;
        int tmp1=current.current,waiting=0;
        int tmp3=0;
        if(trafic_lights[tmp1])//因为这个数可能为0,所以一定要加上这个条件,不然会因为除以0
//而导致runtime error
            tmp3=tim[tmp1]/trafic_lights[tmp1];
        if((tmp3)%2!=0)//红绿灯时间
            waiting+=(tmp3+1)*trafic_lights[tmp1]-tim[tmp1];
        for(int i=heads[tmp1]; i!=-1; i=nodes[i].next)
        {
            int tmp2=nodes[i].toward;
            if(tim[tmp2]>tim[tmp1]+nodes[i].value+waiting)
            {
                tim[tmp2]=tim[tmp1]+nodes[i].value+waiting;
                info u6={tmp2,tim[tmp2]};
                pq.push(u6);
            }
        }
    }
}
int DETERMINATION()
{
    int t;
    din(t);
    while(t--)
    {
        initialization();
        int n,m;
        din(n),din(m);
        for(int i=1; i<=n; i++)
            din(trafic_lights[i]);
        int tmp1,tmp2,tmp3;
        for(int i=1; i<=m; i++)
        {
            din(tmp1),din(tmp2),din(tmp3);
            construction(tmp1,tmp2,tmp3);
            construction(tmp2,tmp1,tmp3);
        }
        int st,des;
        din(st),din(des);
        dijkstra(st,des);
        printlnd(tim[des]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43874261/article/details/89574638