• bzoj2200拓扑排序+最短路+联通块


    自己写的不知道哪里wa了,明明和网上的代码差不多。,。

    /*
    给定一张图,有的边是无向边,有的是有向边,有向边不会出现在环中,且有可能是负权值 
    现在给定起点s,求出s到其余所有点的最短路长度
    任何存在负权边的图都不可以用dij(有向图,无向图,有环图,无环图)
    比如(1,2,8),(1,3,10)(3,2,-5),显然1-3的最短路径是5,但是dij求出的就是8 
    并且spfa超时
    
    利用本题的无向边无 负权,且单向边不会出现在环中,先再每个联通块内求dij,然后用拓扑排序处理联通块之间的距离 
    先将所有无向边加入图,然后求出所有联通块,将联通块缩点
    然后再加入有向边,按拓扑排序进行
    算法流程:
        1.把双向边加入图中,确定所有联通块,并染色
        2.把单向边加入图中,确定所有的联通块的出度入度,只有S所在的联通块入度为0情况下才有解 
        3.开始拓扑排序,初始队列q中仅有c[S]联通块,同时建立dist数组,dist[s]=0 
        4.不断取出队头联通块,在联通块内进行堆优化的dij
            a.把联通块内的所有结点加入堆
            b.从堆中取出d[x]最小的结点,若x已经在最短路集合中,continue 
            c.遍历x的所有边(x,y,z),进行松弛
                如果y是联通块内的,并且y被更新,则把y插入堆中
                若y是其他联通块的,那么in[c[y]]--,如果减到了0,就把c[y]加入队尾          
    */
    #include<bits/stdc++.h>
    #include<vector>
    #include<queue>
    using namespace std;
    #define maxn 25005
    #define maxm 50005
    #define ll long long 
    struct Edge{int to,nxt,w,flag;}edge[maxm<<2];
    int head[maxn],tot,in[maxn],t,r,p,s;
    void init(){
        memset(head,-1,sizeof head);
        tot=0;
    }
    void addedge(int u,int v,int w,int flag){
        edge[tot].to=v;edge[tot].w=w;edge[tot].flag=flag;
        edge[tot].nxt=head[u];head[u]=tot++;
    }
    
    int c[maxn],cnt;
    vector<int>vec[maxn];
    void dfs(int u){//染色
        c[u]=cnt;
        vec[cnt].push_back(u);
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(c[v]==0)dfs(v);
        } 
    }
    
    int d[maxn],vis[maxn],used[maxn];
    int main(){
        while(cin>>t>>r>>p>>s){
            init();
            int u,v,w;
            for(int i=1;i<=r;i++){
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w,1);
                addedge(v,u,w,1);
            }
            
            memset(c,0,sizeof c);
            for(int i=1;i<=t;i++)
                if(!c[i]){
                    cnt++;
                    vec[cnt].clear();
                    dfs(i);
                }
            
            memset(in,0,sizeof in);
            for(int i=1;i<=r;i++){
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w,0);
                in[c[v]]++;
            }
            
            memset(d,127,sizeof d);
            memset(used,0,sizeof used);
            memset(vis,0,sizeof vis);    
            d[s]=0;
            
            queue<int>q;
            q.push(c[s]);//把s所在联通块入队 
            priority_queue<pair<int,int> >pq;
            while(!q.empty()){
                int u=q.front();q.pop();//从队头取出联通块
                for(int i=0;i<vec[u].size();i++){
                    int v=vec[u][i];
                    pq.push(make_pair(-d[v],v));
                }
                while(!pq.empty()){
                    int x=pq.top().second;pq.pop();
                    if(vis[x])continue;
                    vis[x]=1;
                    for(int i=head[x];i!=-1;i=edge[i].nxt){
                        int y=edge[i].to,z=edge[i].w;
                        if(d[y]>d[x]+z){
                            if(c[x]==c[y]){
                                d[y]=d[x]+z;
                                pq.push(make_pair(-d[y],y));
                            }
                        }
                        if(c[x]!=c[y]){
                            d[y]=min(d[x]+z,d[y]);
                            in[c[y]]--;
                            if(in[c[y]]==0)
                                q.push(c[y]);
                        }
                    }
                }    
            }
            for(int i=1;i<=t;i++)
                if(d[i]>0x3f3f3f3f)puts("NO PATH");
                else printf("%d
    ",d[i]);
        }
    } 

    网上的

    #include<bits/stdc++.h>
    #define ll long long
    #define fo(i,j,n) for(register int i=j; i<=n; ++i)
    using namespace std;
    const int N = 25005,M = 150005, INF=0x3f3f3f3f; // M为双向边加单向边
    int T,R,P,S,d[N];
    int head[N],Next[M],ver[M],edge[M],tot;
    bool v[N];
    int c[N],totc,deg[N];
    queue<int> q; // 联通块的拓扑序
    priority_queue<pair<int, int> > Q; // Dij 
    void add(int x,int y, int z){
        ver[++tot]=y, edge[tot]=z;
        Next[tot]=head[x], head[x]=tot;
    }
    void dfs(int x){
        for(int i=head[x]; i; i=Next[i]){
            int y = ver[i];
            if(!c[y]){
                c[y]=totc;
                dfs(y);
            }
        }
    }
    void Dijkstra(){
        while(Q.size()){
            int x = Q.top().second; Q.pop();
            if(v[x])continue;
            v[x] = 1;
            for(int i=head[x]; i; i=Next[i]){
                int y = ver[i], wei = edge[i];
                if(d[y] > d[x]+wei){
                    d[y] = d[x]+wei;
                    if(c[y]==c[x]) Q.push(make_pair(-d[y], y));
                }
                // 对遍历到的点,判断是否不同联通块
                // 联通块入度减少,并且判0 
                if(c[x]!=c[y] && !--deg[c[y]])q.push(c[y]); 
            }
        }
    }
    int main(){
        cin>>T>>R>>P>>S;
        int x,y,z;
        fo(i,1,R){
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z); add(y,x,z);
        }
        // 划分联通块 
        fo(i,1,T){
            if(!c[i]){
                c[i]=++totc;
                dfs(i);
            }
        }
        fo(i,1,P){
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            ++deg[c[y]]; // 联通块的入度 
        }
        // 联通块之间进行拓扑排序
        q.push(c[S]); // 先加入起点
        fo(i,1,totc)if(!deg[i])q.push(i); // 加入0度的联通块
        // topsort
        memset(d, 127, sizeof(d)); // 这里最大值不能为0x3f,0x7f对应127 
        d[S] = 0;
        while(q.size()){
            int i = q.front(); q.pop();
            fo(j,1,T)
                if(c[j]==i)
                    Q.push(make_pair(-d[j], j)); // 联通块 
            Dijkstra();
        } 
        fo(i,1,T){
            if(d[i]>INF)puts("NO PATH");
            else printf("%d
    ",d[i]);
        }
    } 
  • 相关阅读:
    快速幂
    1112个人赛,最长回文串常见算法讨论
    11-05-sdust-个人赛赛后随想
    UVA 1149 Bin Packing
    UVa 1608,Non-boring sequences
    UVa 10954,Add All
    UVa 714,Copying Books
    Careercup
    Careercup
    Careercup
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10477212.html
Copyright © 2020-2023  润新知