• 2019ICPC(银川)


    Delivery Route

    题目:有n个派送点,x条双向边,y条单向边,出发点是s,双向边的权值均为正,单向边的权值可以为负数,对于单向边给出了一个限制:如果u->v成立,则v->u一定不成立。问,从s出发,到其他所有点的最短路是多少(包括s)。

    思路:对于单向边的限制,我们可以这么理解:双向边相连接的点一定组成一个强连通分量,如果一条单向边存在于某个强连通分量中,可以得出:如果“u -> v”,则一定“v -> u”,可以推出单向边一定只存在于连接两个强连通分量,且还可以推出,强连通分量缩点后,连上单向边,此时的图一定是一个有向无环图,于是给出的限制"对于单向边给出了一个限制:如果u->v成立,则v->u一定不成立。"完全成立,于是图的性质我们分析完了。

    ①似乎这个图的性质可以直接跑dijkstra,的确可以,但是负权边的存在复杂度太大。

    ②每个强连通分量都可以dijkstra,且图存在拓扑排序,不如让入度为0的缩点先跑dijkstra,然后一条单向边只影响其他强连通分量的一个点的距离,然后按照拓扑序来确定每个强连通分量跑dijkstra的顺序。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <queue>
      5 
      6 #define ll long long
      7 #define pb push_back
      8 #define fi first
      9 #define se second
     10 
     11 using namespace std;
     12 
     13 const int N = 25000 + 10;
     14 const int M = 50000 + 10;
     15 const ll INF = 1e10;
     16 struct Edge{
     17     int to, nxt, w;
     18 }e[M << 2];
     19 struct node{
     20     int u, v, w;
     21 };
     22 struct tmp{
     23     int now;
     24     ll w;
     25     bool friend operator<(const tmp& a, const tmp& b){
     26         return a.w > b.w;
     27     }
     28 };
     29 int head[N], scc[N], du[N], vis[N], ok[N]; 
     30 ll dis[N];
     31 vector<node > vp[N];//单向边
     32 vector<int > belong[N];//属于哪个scc
     33 vector<int > mp[N];//存边
     34 priority_queue<tmp > pque;
     35 int n, x, y, s, tot, col;
     36 
     37 inline void add(int u, int v, int w){
     38     e[tot].to = v; e[tot].nxt = head[u];
     39     e[tot].w = w; head[u] = tot++;
     40 }
     41 
     42 //缩点
     43 void dfs(int now){
     44     scc[now] = col;
     45     belong[col].pb(now);
     46     for(int o = head[now]; ~o; o = e[o].nxt)
     47         if(!scc[e[o].to]) dfs(e[o].to);
     48 }
     49 
     50 //检测这个点是不是有效点
     51 void check(int now){
     52     ok[now] = 1;
     53     for(auto to : mp[now])
     54         if(!ok[to]) check(to);
     55 }
     56 
     57 void dijkstra(int ss){
     58     while(!pque.empty()) pque.pop();
     59     if(ss == s) pque.push({ss, dis[ss]}); //图一定是从出发点s开始的
     60     else{
     61         //相当于从一个超级源点出发
     62         for(auto it : belong[scc[ss]]) pque.push({it, dis[it]});
     63     }
     64     while(!pque.empty()){
     65         int u = pque.top().now;
     66         pque.pop();
     67         if(vis[u]) continue;
     68         vis[u] = 1;
     69         for(int o = head[u]; ~o; o = e[o].nxt){
     70             if(dis[u] + e[o].w < dis[e[o].to]){
     71                 dis[e[o].to] = dis[u] + e[o].w;
     72                 pque.push({e[o].to, dis[e[o].to]});
     73             }
     74         }
     75     }
     76 }
     77 
     78 void top_sort(){
     79     queue<int > que;    
     80     que.push(scc[s]);//满足的图 应该是从s的连通图出发的拓扑图
     81     dijkstra(s);
     82     while(!que.empty()){
     83         int inx = que.front();
     84         que.pop();
     85         for(auto it : vp[inx]){
     86             //一条单向边影响一个点的距离
     87             if(dis[it.u] + it.w < dis[it.v]){
     88                 dis[it.v] = dis[it.u] + it.w;
     89             }
     90             //入度0,跑dijkstra
     91             if(--du[scc[it.v]] == 0){
     92                 que.push(scc[it.v]);
     93                 dijkstra(it.v);
     94             }
     95         }
     96     }
     97 }
     98 
     99 
    100 void solve(){
    101     scanf("%d%d%d%d", &n, &x, &y, &s);
    102     for(int i = 1; i <= n; ++i) head[i] = -1; tot = 0;
    103     for(int i = 1; i <= n; ++i) dis[i] = INF; dis[s] = 0;
    104     int u, v, w;
    105     for(int i = 1; i <= x; ++i){
    106         scanf("%d%d%d", &u, &v, &w);
    107         add(u, v, w); add(v, u, w);
    108         mp[u].pb(v); mp[v].pb(u);
    109     }
    110 
    111     vector<node > tmp;
    112     for(int i = 1; i <= y; ++i){
    113         scanf("%d%d%d", &u, &v, &w);
    114         tmp.pb({u, v, w});
    115         mp[u].pb(v);
    116     }
    117     //图一定是从出发点s开始的,所以从s出发遍历图,无法到达的点,就是无法到达的点
    118     //检测这个点是不是有效点
    119     check(s);
    120     //缩点
    121     for(int i = 1; i <= n; ++i){
    122         if(!scc[i] && ok[i]){   
    123             ++col;
    124             dfs(i);
    125         }
    126     }
    127     //入度统计
    128     for(auto x : tmp){
    129         if(ok[x.u] && ok[x.v]){//有效点
    130             vp[scc[x.u]].pb(x);
    131             ++du[scc[x.v]];
    132         }
    133     }
    134     top_sort();//拓扑序
    135     for(int i = 1; i <= n; ++i){
    136         if(dis[i] == INF) printf("NO PATH
    ");
    137         else printf("%lld
    ", dis[i]);
    138     }
    139 }
    140 
    141 int main(){
    142 
    143     solve();
    144 
    145     return 0;
    146 }
    147 
    148 /*
    149 7 5 3 4
    150 1 2 5 
    151 3 4 5
    152 5 6 10
    153 5 7 4
    154 6 7 105
    155 3 5 -100 
    156 4 6 -100 
    157 7 2 -100
    158 */

     

  • 相关阅读:
    asp.net core过滤器记录响应对象
    ef core实现无感知软删除
    Egret资源跨域问题
    ASP.Net Core中使用jquery-ajax-unobtrusive替换Ajax.BeginForm
    把.Net开发环境迁移到Linux上去
    Mysql8.0升级后,Navicat连接报错caching_sha2_password 问题
    改MySQL的编码方式,解决jdbc MySQL中文乱码问题
    怡红公子专属网址导航
    html以前没有学到的标签
    有哪些质量上乘的程序员必关注的网站或论坛
  • 原文地址:https://www.cnblogs.com/SSummerZzz/p/12655418.html
Copyright © 2020-2023  润新知