zoukankan      html  css  js  c++  java
  • 【BZOJ2200】道路和航线

    这是一道非常不错的题目,融合了多种算法。

    首先这是一道单源最短路问题,一个显然的做法就是直接用相关的算法解决,但是本题有负权边,所以我们不能用dijstra算法,只能用spfa,但是如果数据是精心设计,那么spfa算法很可能被卡死,所以简单的单源最短路算法无法直接通过本题。

    仔细分析,这道题有一个特点:双向边都没有负权,负权只会出现在单向边当中,因此我们把这张图划分成若干个仅由双向边组成的联通块,显然他们都是强联通的,而单向边连接两个连通块构成了一个有向无环图,我们先在每一个连通块内做dijstra,此时边权无负数,所以可行,我们再用拓扑排序处理连通块之间的问题,问题就解决了。

    具体地讲,我们读入双向边之后进行dfs,求出每一个点属于哪一个联通块,接着读入单向边并且统计每一个联通块的入度(把一个联通块看成一个点),方便拓扑排序。把源点所属的“块”和入度为0的“块”入队,进行拓扑排序,在处理每一个“块”时,进行dijstra,如果扩展的点和被扩展的点属于同一个联通块,那么接着进行dijstra,否则就按照拓扑排序的步骤,将其入度减一,判断是否为零入队……

    最后,我们扫一遍每一个点,判断即可。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <queue>
     6 using namespace std;
     7 #define inf 0x3f3f3f3f
     8 inline int read() {
     9     int ret=0;
    10     int op=1;
    11     char c=getchar();
    12     while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();}
    13     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
    14     return ret*op;
    15 }
    16 struct node {
    17     int next,to,dis;
    18 }a[200010];
    19 int num,head[200010];
    20 int t,r,p,s;
    21 inline void add(int from,int to,int dis) {
    22     a[++num].next=head[from]; a[num].to=to; a[num].dis=dis; head[from]=num;
    23 }
    24 int be[25010],tot,deg[25010];
    25 int vis[25010],dis[25010];
    26 queue<int> q;
    27 priority_queue<pair<int,int> >Q;
    28 void dfs(int u) {
    29     for(int i=head[u];i;i=a[i].next) {
    30         int v=a[i].to;
    31         if(!be[v]) {
    32             be[v]=be[u];
    33             dfs(v);
    34         }
    35     }
    36 }
    37 int main() {
    38     t=read(); r=read(); p=read(); s=read();
    39     for(int i=1;i<=r;i++) {
    40         int x=read(),y=read(),z=read();
    41         add(x,y,z);
    42         add(y,x,z);
    43     }
    44     for(int i=1;i<=t;i++)
    45         if(!be[i]) {
    46             be[i]=++tot;
    47             dfs(i);
    48         }
    49     for(int i=1;i<=p;i++) {
    50         int x=read(),y=read(),z=read();
    51         add(x,y,z);
    52         deg[be[y]]++;
    53     }
    54     memset(vis,0,sizeof(vis));
    55     memset(dis,0x7f,sizeof(dis));
    56     dis[s]=0;
    57     q.push(be[s]);
    58     for(int i=1;i<=tot;i++)
    59         if(!deg[i]) q.push(i);
    60     while(!q.empty()) {
    61         int now=q.front();
    62         q.pop();
    63         for(int i=1;i<=t;i++)
    64             if(be[i]==now) Q.push(make_pair(-dis[i],i));
    65         while(!Q.empty()) {
    66             int u=Q.top().second;
    67             Q.pop();
    68             if(vis[u]) continue ;
    69             vis[u]=1;
    70             for(int j=head[u];j;j=a[j].next) {
    71                 int k=a[j].to;
    72                 if(dis[k]>dis[u]+a[j].dis) {
    73                     dis[k]=dis[u]+a[j].dis;
    74                     if(be[u]==be[k]) Q.push(make_pair(-dis[k],k));
    75                 }
    76                 if(be[u]!=be[k]&&--deg[be[k]]==0) q.push(be[k]);
    77             }
    78         }
    79     }
    80     for(int i=1;i<=t;i++)
    81         if(dis[i]>inf) puts("NO PATH");
    82         else printf("%d
    ",dis[i]);
    83     return 0;
    84 }
    AC Code
  • 相关阅读:
    wireshark 导出所有filter出来的包
    ubuntu 14.04安装pypcap
    激活windows7 企业版小记
    ubuntu 14.04 以root权限启动chrome
    git clone Linux 源码并切换TAG
    ubuntu 14.04 ns2.35 ***buffer overflow detected **: ns terminated解决办法
    我离baidu.com有几跳
    linux tcp超时重传实现分析
    dpctl 工具使用
    由于log太多导致ubuntu硬盘空间满了,进入不了系统解决办法
  • 原文地址:https://www.cnblogs.com/shl-blog/p/10776342.html
Copyright © 2011-2022 走看看