zoukankan      html  css  js  c++  java
  • 「BZOJ1576」[Usaco2009 Jan] 安全路经Travel------------------------P2934 [USACO09JAN]安全出行Safe Travel

    原题地址

    题目描述

    Gremlins have infested the farm. These nasty, ugly fairy-like

    creatures thwart the cows as each one walks from the barn (conveniently located at pasture_1) to the other fields, with cow_i traveling to from pasture_1 to pasture_i. Each gremlin is personalized and knows the quickest path that cow_i normally takes to pasture_i. Gremlin_i waits for cow_i in the middle of the final cowpath of the quickest route to pasture_i, hoping to harass cow_i.

    Each of the cows, of course, wishes not to be harassed and thus chooses an at least slightly different route from pasture_1 (the barn) to pasture_i.

    Compute the best time to traverse each of these new not-quite-quickest routes that enable each cow_i that avoid gremlin_i who is located on the final cowpath of the quickest route from pasture_1 to

    pasture_i.

    As usual, the M (2 <= M <= 200,000) cowpaths conveniently numbered 1..M are bidirectional and enable travel to all N (3 <= N <= 100,000) pastures conveniently numbered 1..N. Cowpath i connects pastures a_i (1 <= a_i <= N) and b_i (1 <= b_i <= N) and requires t_i (1 <= t_i <= 1,000) time to traverse. No two cowpaths connect the same two pastures, and no path connects a pasture to itself (a_i != b_i). Best of all, the shortest path regularly taken by cow_i from pasture_1 to pasture_i is unique in all the test data supplied to your program.

    By way of example, consider these pastures, cowpaths, and [times]:

    1--[2]--2-------+ 
    |       |       | 
    [2]     [1]     [3] 
    |       |       | 
    +-------3--[4]--4
    
    TRAVEL     BEST ROUTE   BEST TIME   LAST PATH 
    p_1 to p_2       1->2          2         1->2 
    p_1 to p_3       1->3          2         1->3 
    p_1 to p_4      1->2->4        5         2->4 
    

    When gremlins are present:

    TRAVEL     BEST ROUTE   BEST TIME    AVOID 
    p_1 to p_2     1->3->2         3         1->2 
    p_1 to p_3     1->2->3         3         1->3 
    p_1 to p_4     1->3->4         6         2->4 
    

    For 20% of the test data, N <= 200.

    For 50% of the test data, N <= 3000.

    TIME LIMIT: 3 Seconds

    MEMORY LIMIT: 64 MB

    Gremlins最近在农场上泛滥,它们经常会阻止牛们从农庄(牛棚_1)走到别的牛棚(牛_i的目的 地是牛棚_i).每一个gremlin只认识牛_i并且知道牛_i一般走到牛棚_i的最短路经.所以它 们在牛_i到牛棚_i之前的最后一条牛路上等牛_i. 当然,牛不愿意遇到Gremlins,所以准备找 一条稍微不同的路经从牛棚_1走到牛棚_i.所以,请你为每一头牛_i找出避免gremlin_i的最 短路经的长度.

    和以往一样, 农场上的M (2 <= M <= 200,000)条双向牛路编号为1..M并且能让所有牛到 达它们的目的地, N(3 <= N <= 100,000)个编号为1..N的牛棚.牛路i连接牛棚a_i (1 <= a_i <= N)和b_i (1 <= b_i <= N)并且需要时间t_i (1 <=t_i <= 1,000)通过. 没有两条牛路连接同样的牛棚,所有牛路满足a_i!=b_i.在所有数据中,牛_i使用的牛棚_1到牛 棚_i的最短路经是唯一的.

    输入格式

    * Line 1: Two space-separated integers: N and M

    * Lines 2..M+1: Three space-separated integers: a_i, b_i, and t_i

    输出格式

    * Lines 1..N-1: Line i contains the smallest time required to travel from pasture_1 to pasture_i+1 while avoiding the final cowpath of the shortest path from pasture_1 to pasture_i+1. If no such path exists from pasture_1 to pasture_i+1, output -1 alone on the line.

    输入输出样例

    输入 #1
    4 5 
    1 2 2 
    1 3 2 
    3 4 4 
    3 2 1 
    2 4 3 
    
    输出 #1
    3 
    3 
    6 
    

    打题的艰辛历程

    • 这题,只要是个想我一样这么弱的人第一反应就是次短路,把断的边给连上跑一次次短路就行了,然后隔壁大佬给了一组数据,他有可能次短路也要走这条边,然后这个思路就死了。
    • 过了一会又瞎YY出来了一个算法,找出终点的父节点,然后从这个父节点开始跑最短路再加上根节点到父节点的距离就可以了,就这个算法一开始还没看出来是错的,还瞎搞了一个什么算法,还一本正经的试了样例,发现错了,然后才发现他可以从父节点之前就绕道走。。。。
    • 最后去看了题解,又瞎搞了什么最短路树,调了一上午,发现有一个字母打错了。。。。
    • 最后终于过了
    • 总结这题就是折磨人的。。。

    思路:

    • 这题就是一个最短路树,最短路树,就是一棵树,根节点到每个节点的长度就是原图上起点到这个点的最短路(就是1到每个节点的最短路径路过的边所构成的集合)
    • 我们要找一个点对(x,y)x,y之间有连边,但不在最短路树上,y在节点i的子树中,而x则不在,x同样也不是i,y的祖先,dis是最短路径,w是路径长度。
    • 所以我们要找的节点路径就是dis(x)+dis(y)-dis(i)+w(x,y);这个东西比较抽象,可以动手画图看一下。
    • 由于dis(i)是一定的,所以我们就要维护dis(x)+dis(y)+w(x,y)的最小值,因为太懒,就直接排个序算了,慢也慢不到哪去,STL里的sort好像有什么搞不懂的优化,反正排序用他就可以了。
    • 这样我们就选出了不在树上的边,排下序。更新好答案。
    • 在一个点被更新之后,那这个点的答案就一定最优,所以对上面那一堆式子,第一次更新就一定会是他的最优解。
    • 然后就可以用冰茶姬去维护每一个只搞了一次。
    • 然后又可以发现每一次更新都更新了x->lca(x,y)和y->lca(x,y)的所有点。因为如果更新到了LCA(x,y),那x,y就在同一棵子树里了,而我们可以更新的前提就是X,Y不在一棵子树中,题目说了x-y不会是i的父边,所以就一个一个像LCA那样去跳,一边跳一遍更新,知道LCA,然后改一下冰茶姬,最后完美结束。

    最后放一下代码,千万别用SPFA,会T掉很多。。。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <queue>
      5 #include <cstring>
      6 #include <queue>
      7 using namespace std;
      8 const int maxn = 100010;
      9 const int maxm = 400010;
     10 
     11 inline int read()
     12 {
     13     int res = 0;
     14     bool flag = 0;
     15     char c = getchar();
     16     while (c < '0' or c > '9')
     17     {
     18         if (c == '-') flag = 1;
     19         c = getchar();
     20     }
     21     while (c >= '0' and c <= '9')
     22     {
     23         res = res * 10 + c - '0';
     24         c = getchar();
     25     }
     26     return flag ? -res : res;
     27 }
     28 
     29 int n, m;
     30 int a [maxm], b[maxm], c[maxm];
     31 int what[maxm];
     32 int ins[maxm]; 
     33 bool iiis[maxm]; 
     34 int father[maxn];
     35 int fa[maxn];
     36 int ans[maxn]; 
     37 
     38 int find(int x)
     39 {
     40     return x==fa[x]?x:fa[x]=find(fa[x]);
     41 }
     42 
     43 struct edge
     44 {
     45     int next;
     46     int to;
     47     int val;
     48 }way[maxm];
     49 
     50 int head[maxn], tot;
     51 inline void add (int x , int y , int z , int GG)
     52 {
     53     way[++tot].next = head[x];
     54     way[tot].to = y;
     55     way[tot].val = z;
     56     what[tot] = GG;
     57     head[x] = tot;
     58 }
     59 inline void add (int x , int y)
     60 {
     61     way[++tot].next = head[x];
     62     way[tot].to=y;
     63     head[x]=tot;
     64 }
     65 struct date
     66 {
     67     int x;
     68     int y;
     69     int w;
     70 }usaco[maxm];
     71 
     72 bool cmp(date a, date b)
     73 {
     74     return a.w < b.w;
     75 }
     76 
     77 
     78 int dfs(int x)
     79 {
     80     for(int i=head[x];i;i=way[i].next)
     81     {
     82         int to=way[i].to;
     83         if(to==father[x])
     84         {
     85             continue;
     86         }
     87         father[to]=x;
     88         dfs(to);
     89     }
     90 }
     91 
     92 struct dij{int x, w;};
     93 
     94 bool operator <(const dij &a,const dij &b)
     95 {
     96     return a.w > b.w;
     97 }
     98 
     99 int dis[maxn];
    100 bool vis[maxn];
    101 
    102 int dijkstra(int qa)
    103 {
    104     memset(dis,0x3f,sizeof(dis));
    105     priority_queue < dij > q;
    106     dis[qa]=0;
    107     q.push((dij){qa,0});
    108     while(!q.empty())
    109     {
    110         dij t=q.top();
    111         q.pop();
    112         int x=t.x;
    113         if(vis[x])
    114         {
    115             continue;
    116         }
    117         vis[x]=1;
    118         for(int i=head[x];i;i=way[i].next)
    119         {
    120             int to=way[i].to;
    121             if(!vis[to]&&dis[to]>dis[x]+way[i].val)
    122             {
    123                 ins[to]=what[i];
    124                 dis[to]=dis[x]+way[i].val;
    125                 q.push((dij){to,dis[to]});
    126             }
    127         }
    128     }
    129 }
    130 int main()
    131 {
    132     //freopen("testdata.in","r",stdin);
    133     n=read();
    134     m=read();
    135     for(int i=1;i<=m;i++)
    136     {
    137         a[i]=read();
    138         b[i]=read();
    139         c[i]=read();
    140         add(a[i],b[i],c[i],i);
    141         add(b[i],a[i],c[i],i);
    142     }
    143     dijkstra(1);
    144     tot=0;
    145     memset(head,0,sizeof(head));
    146     for(int i=2;i<=n;i++)
    147     {
    148         int x=ins[i];
    149         add(a[x],b[x]);
    150         add(b[x],a[x]);
    151         iiis[x]=1;
    152     }
    153     dfs(1);
    154     int sum=0;
    155     for(int i=1;i<=m;i++)
    156     {
    157         if(iiis[i])
    158         {
    159             continue;
    160         }
    161         usaco[++sum]=(date){a[i],b[i],dis[a[i]]+dis[b[i]]+c[i]};
    162     }
    163     sort(usaco+1,usaco+1+sum,cmp);
    164     for(int i=1;i<=n;i++)
    165     {
    166         fa[i]=i;
    167         ans[i]=-1;
    168     }
    169     for(int i=1;i<=sum;i++)
    170     {
    171         int x=usaco[i].x;
    172         int y=usaco[i].y;
    173         x=find(x);
    174         y=find(y);
    175         while(x!=y)
    176         {
    177             if(dis[x]<dis[y])
    178             {
    179                 swap(x,y);
    180             }
    181             ans[x]=usaco[i].w-dis[x];
    182             fa[x]=father[x];
    183             x=find(x);
    184         }
    185     }
    186     for(int i=2;i<=n;i++)
    187     {
    188         printf("%d
    ",ans[i]);
    189     //    cout<<ans[i]<<endl;
    190     }
    191     return 0;
    192 }
  • 相关阅读:
    Java代码生成器多表配置优化,增加自定义实体功能
    Java代码生成器加入postgresql数据库、HikariCP连接池、swagger2支持!
    SSM/SpringBoot代码生成器全面升级—增加全新前后端分离响应式主题,修复若干Bug
    记一次真实的线上事故:一个update引发的惨案!
    昨日学习安排
    C++个人学习笔记
    C++位运算符
    随手写事two
    随手写事
    Tomcat一对多遇到得问题
  • 原文地址:https://www.cnblogs.com/2529102757ab/p/11441774.html
Copyright © 2011-2022 走看看