zoukankan      html  css  js  c++  java
  • 入门OJ:最短路径树入门

    题目描述

    n个城市用m条双向公路连接,使得任意两个城市都能直接或间接地连通。其中城市编号为1..n,公路编号为1..m。任意个两个城市间的货物运输会选择最短路径,把这n*(n-1)条最短路径的和记为S。现在你来寻找关键公路r,公路r必须满足:当r堵塞之后,S的值会变大(如果r堵塞后使得城市u和v不可达,则S为无穷大)。

    输入格式

    第1行包含两个整数n,m,接下来的m行,每行用三个整数描述一条公路a,b,len(1<=a,b<=n),表示城市a和城市b之间的公路长度为len,这些公路依次编号为1..m。

    n<=100,1<=m<=3000,1<=len<=10000。

    输出格式

    从小到大输出关键公路的编号。


    先考虑暴力。

    显然,对于一个点u,如果删去的边不在它到其它点的最短路上,那么S是不会变的。考虑到两点之间的最短路不止一条,我们可以给每个点先建出一棵最短路径树出来,然后枚举最短路径树上的每条边并把它删掉,再跑一遍最短路,看S是否变大即可。如果最短路用dijkstra+heap来做,这个过程的时间复杂度就是:

    [O(N*((N+M)log(N+M)+N*(N+M)log(N+M))) ]

    也就N^3logN的级别。可以过这题。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #define maxn 101
    #define maxm 3001
    using namespace std;
     
    vector<int> to[maxn],w[maxn],id[maxn];
    int dis[maxn],treeid[maxn];
    bool vis[maxn],lzs[maxm];
    int n,m;
     
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
     
    inline void dijkstra(const int &s,const int &del){
        priority_queue< pair<int,int>,vector< pair<int,int> >,greater< pair<int,int> > > q;
        memset(vis,false,sizeof vis),memset(dis,0x3f,sizeof dis);
        q.push(make_pair(0,s)),dis[s]=0;
        while(q.size()){
            int u=q.top().second; q.pop();
            if(vis[u]) continue; vis[u]=true;
            for(register int i=0;i<to[u].size();i++) if(id[u][i]!=del){
                int v=to[u][i];
                if(dis[v]>dis[u]+w[u][i]){
                    dis[v]=dis[u]+w[u][i],q.push(make_pair(dis[v],v));
                    if(!del) treeid[v]=id[u][i];
                }
            }
        }
    }
     
     
    inline void out(int a){
        if(a>=10)out(a/10);
        putchar(a%10+'0');
    }
     
    int main(){
        n=read(),m=read();
        memset(dis,0x3f,sizeof dis);
        for(register int i=1;i<=m;i++){
            int u=read(),v=read(),_w=read();
            to[u].push_back(v),w[u].push_back(_w),id[u].push_back(i);
            to[v].push_back(u),w[v].push_back(_w),id[v].push_back(i);
        }
     
        for(register int i=1;i<=n;i++){
            dijkstra(i,0);
            int sum=0; for(register int j=1;j<=n;j++) sum+=dis[j];
            for(register int j=1;j<=n;j++) if(treeid[j]&&!lzs[treeid[j]]){
                dijkstra(i,treeid[j]);
                int cnt=0; for(register int k=1;k<=n;k++) cnt+=dis[k];
                if(cnt>sum) lzs[treeid[j]]=true;
            }
        }
     
        bool flag=false;
        for(register int i=1;i<=m;i++) if(lzs[i]){
            out(i),putchar('
    ');
        }
        return 0;
    }
    
  • 相关阅读:
    如何使用robots.txt及其详解
    有序列表
    前端开发大众手册(包括工具、网址、经验等)
    转载:Tim O'Reilly与John Battelle谈即将开幕的Web
    转载:iframe全跨域高度自适应解决方案
    javascript 学习笔记
    【C#文件夹锁】C#文件夹加锁小工具
    Pro Silverlight 5 in C# 分享
    在Winform窗体中使用WPF控件(附源码)
    【C#文件锁】C#加密解密文件小工具
  • 原文地址:https://www.cnblogs.com/akura/p/10951756.html
Copyright © 2011-2022 走看看