zoukankan      html  css  js  c++  java
  • POJ3463 Sightseeing

    Sightseeing
    Time Limit: 2000MS   Memory Limit: 65536K
    Total Submissions: 9535   Accepted: 3352

    Description

    Tour operator Your Personal Holiday organises guided bus trips across the Benelux. Every day the bus moves from one city S to another city F. On this way, the tourists in the bus can see the sights alongside the route travelled. Moreover, the bus makes a number of stops (zero or more) at some beautiful cities, where the tourists get out to see the local sights.

    Different groups of tourists may have different preferences for the sights they want to see, and thus for the route to be taken from S to F. Therefore, Your Personal Holiday wants to offer its clients a choice from many different routes. As hotels have been booked in advance, the starting city S and the final city F, though, are fixed. Two routes from S to F are considered different if there is at least one road from a city A to a city B which is part of one route, but not of the other route.

    There is a restriction on the routes that the tourists may choose from. To leave enough time for the sightseeing at the stops (and to avoid using too much fuel), the bus has to take a short route from S to F. It has to be either a route with minimal distance, or a route which is one distance unit longer than the minimal distance. Indeed, by allowing routes that are one distance unit longer, the tourists may have more choice than by restricting them to exactly the minimal routes. This enhances the impression of a personal holiday.

    For example, for the above road map, there are two minimal routes from S = 1 to F = 5: 1 → 2 → 5 and 1 → 3 → 5, both of length 6. There is one route that is one distance unit longer: 1 → 3 → 4 → 5, of length 7.

    Now, given a (partial) road map of the Benelux and two cities S and F, tour operator Your Personal Holiday likes to know how many different routes it can offer to its clients, under the above restriction on the route length.

    Input

    The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:

    • One line with two integers N and M, separated by a single space, with 2 ≤ N ≤ 1,000 and 1 ≤ M ≤ 10, 000: the number of cities and the number of roads in the road map.

    • M lines, each with three integers A, B and L, separated by single spaces, with 1 ≤ A, BN, AB and 1 ≤ L ≤ 1,000, describing a road from city A to city B with length L.

      The roads are unidirectional. Hence, if there is a road from A to B, then there is not necessarily also a road from B to A. There may be different roads from a city A to a city B.

    • One line with two integers S and F, separated by a single space, with 1 ≤ S, FN and SF: the starting city and the final city of the route.

      There will be at least one route from S to F.

    Output

    For every test case in the input file, the output should contain a single number, on a single line: the number of routes of minimal length or one distance unit longer. Test cases are such, that this number is at most 109 = 1,000,000,000.

    Sample Input

    2
    5 8
    1 2 3
    1 3 2
    1 4 5
    2 3 1
    2 5 3
    3 4 2
    3 5 4
    4 5 3
    1 5
    5 6
    2 3 1
    3 2 1
    3 1 10
    4 5 2
    5 2 7
    5 2 7
    4 1

    Sample Output

    3
    2

    Hint

    The first test case above corresponds to the picture in the problem description.

    Source

     
    【题解】
    用mi[0][i]和len[0][i]记录最短路和最短路条数
    用mi[1][i]和len[1][i]记录严格次短路和严格次短路条数
    用dijkstra,更新的时候最短路和次短路都要压入堆
    转移即可(其他博客都有)
    if(mi[0][v] == mi[d][u] + edge[pos].w) len[0][v] += len[d][u];
    else if(mi[1][v] == mi[d][u] + edge[pos].w) len[1][v] += len[d][u];
    else if(mi[0][v] > mi[d][u] + edge[pos].w) 
    	mi[1][v] = mi[0][v], len[1][v] = len[0][v];
    	mi[0][v] = mi[d][u] + edge[pos].w, len[0][v] = len[d][u];
    else if(mi[1][v] > mi[d][u] + edge[pos].w)
    	mi[1][v] = mi[d][u] + edge[pos].w, len[1][v] = len[d][u];
    
    我们这里着重来试着用显然法(唔)证明一下算法的正确性
    看懂这部分你得先理解dijkstra的正确性证明。
    不难发现从堆中一定先取出n个点的点最短路,再
    取出n个点的次短路,所以每个点的mi[0],mi[1]
    先被最短路更新mi[0]和mi[1],再被次短路更新mi[1]
    不能只用最短路更新,可能会导致最短路=次短路的情况
    大概理解dijkstra的证明,就能用显然法证mi(唔)
     
    我们看len的证明
     
    从小数据看,我们不妨虚设一个点0,使得起点s指向0,边权为0,s的出边全部变为
    0的出边,s的入边还是s的入边。与原图等价。我们把0和s缩成一个点,len[0][s] = 1,
    len[1][s]= 0 就是正确的
    归纳证明
    当我们取出len[0][u]或len[1][u]时,他们已经不可能被更新了,我们假定他们的值是正确的
    对于u指出的所有点v
    len[0][v]可能被更新,len[1][v]也可能被更新
    v可能被所有指向他的点更新,更新他的点都是正确的
    那么当v被取出的时候,没有点可以更新它了,v是正确的
    证毕
    注意用else,不然可能会更新乱掉
     
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <vector>
      4 #include <cstdlib>
      5 #include <cstring>
      6 #include <queue>
      7 #define max(a, b) ((a) > (b) ? (a) : (b))
      8 #define min(a, b) ((a) < (b) ? (a) : (b))
      9 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 
     10 
     11 const int INF = 0x3f3f3f3f;
     12 const int MAXN = 1000 + 10;
     13 const int MAXM = 100000 + 10;
     14 
     15 inline void read(int &x)
     16 {
     17     x = 0;char ch = getchar(), c = ch;
     18     while(ch < '0' || ch > '9') c = ch, ch = getchar();
     19     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
     20     if(c == '-')x = -x; 
     21 }
     22 
     23 struct Edge
     24 {
     25     int u,v,w,next;
     26     Edge(int _u, int _v, int _w, int _next){u = _u;v = _v;w = _w;next = _next;}
     27     Edge(){}
     28 }edge[MAXM << 1];
     29 int head[MAXN], cnt;
     30 inline void insert(int a, int b, int c)
     31 {
     32     edge[++cnt] = Edge(a,b,c,head[a]);
     33     head[a] = cnt;
     34 }
     35 
     36 int tt,n,m,s,t;
     37 
     38 struct Node
     39 {
     40     int v,w,d;
     41     Node(int _v, int _w, int _d){v = _v;w = _w;d = _d;}
     42     Node(){}
     43 };
     44 
     45 int mi[2][MAXN], len[2][MAXN],b[2][MAXN];
     46 
     47 struct cmp
     48 {
     49     bool operator()(Node a, Node b)
     50     {
     51         return a.w > b.w;
     52     }
     53 };
     54 
     55 std::priority_queue<Node, std::vector<Node>, cmp> q; 
     56 
     57 void dijstra()
     58 {
     59     while(q.size())q.pop();
     60     memset(mi, 0x3f, sizeof(mi));
     61     memset(len, 0, sizeof(len));
     62     memset(b, 0, sizeof(b));
     63     len[0][s] = 1;
     64     mi[0][s] = 0;
     65     q.push(Node(s, 0, 0));
     66     int u,v,d;Node now;
     67     while(q.size())
     68     {
     69         now = q.top();q.pop();
     70         if(b[now.d][now.v])continue;
     71         b[now.d][now.v] = 1;
     72         u = now.v;d = now.d;b[d][u] = 1;
     73         for(register int pos = head[u];pos;pos = edge[pos].next)
     74         {
     75             v = edge[pos].v;
     76             if(mi[0][v] == mi[d][u] + edge[pos].w) len[0][v] += len[d][u];
     77             else if(mi[1][v] == mi[d][u] + edge[pos].w) len[1][v] += len[d][u];
     78             else if(mi[0][v] > mi[d][u] + edge[pos].w) 
     79             {
     80                 mi[1][v] = mi[0][v], len[1][v] = len[0][v];
     81                 mi[0][v] = mi[d][u] + edge[pos].w, len[0][v] = len[d][u];
     82                 q.push(Node(v, mi[0][v], 0));
     83                 q.push(Node(v, mi[1][v], 1));
     84             }
     85             else if(mi[1][v] > mi[d][u] + edge[pos].w)
     86             {
     87                 mi[1][v] = mi[d][u] + edge[pos].w, len[1][v] = len[d][u];
     88                 q.push(Node(v, mi[1][v], 1));
     89             }
     90         }
     91     }
     92 }
     93 
     94 int main()
     95 {
     96     read(tt);
     97     for(;tt;--tt)
     98     {
     99         memset(edge, 0, sizeof(edge));
    100         memset(head, 0, sizeof(head));
    101         cnt = 0;
    102         read(n), read(m);
    103         int tmp1, tmp2, tmp3;
    104         for(register int i = 1;i <= m;++ i)
    105         {
    106             read(tmp1), read(tmp2), read(tmp3);
    107             insert(tmp1, tmp2, tmp3);
    108         }
    109         read(s), read(t);
    110         dijstra();
    111         if(mi[0][t] + 1 == mi[1][t])
    112             printf("%d
    ", len[0][t] + len[1][t]);
    113         else
    114             printf("%d
    ", len[0][t]);
    115     }
    116     return 0;
    117 }
    POJ3463
     
  • 相关阅读:
    Python保留最后N个元素
    STL算法
    STL迭代器
    STL容器
    C++总结1
    牛客剑指Offer2
    Vue第一天
    UML
    Java继承和组合代码
    Java15后的sealed阻止继承滥用
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/7606007.html
Copyright © 2011-2022 走看看