zoukankan      html  css  js  c++  java
  • 【百度之星】最短路2

    Time Limit: 6000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 160    Accepted Submission(s): 40

    小 A 是社团里的工具人,有一天他的朋友给了他一个 n 个点,m 条边的正权连通无向图,要他计算所有点两两之间的最短路。

    作为一个工具人,小 A 熟练掌握着 floyd 算法,设 w[i][j] 为原图中 (i,j) 之间的权值最小的边的权值,若没有边则 w[i][j]=无穷大。特别地,若 i=j,则 w[i][j]=0

    Floyd 的 C++ 实现如下:

    ```c++
    for(int k=1;k<=p;k++)
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
      w[i][j]=min(w[i][j],w[i][k]+w[k][j]);
    ```

    当 p=n 时,该代码就是我们所熟知的 floyd,然而小 A 为了让代码跑的更快点,所以想减少 p 的值。

    令 Di,j 为最小的非负整数 x,满足当 p=x 时,点 i 与点 j 之间的最短路被正确计算了。

    现在你需要求 ni=1nj=1Di,j,虽然答案不会很大,但为了显得本题像个计数题,你还是需要将答案对 998244353 取模后输出。

    Input
    第一行一个正整数 T(T30) 表示数据组数

    对于每组数据:

    第一行两个正整数 n,m(1n1000,m2000),表示点数和边数。

    保证最多只有 5 组数据满足 max(n,m)>200 

    接下来 m 行,每行三个正整数 u,v,w 描述一条边权为 w 的边 (u,v),其中 1w109


    Output
    输出 T 行,第 i 行一个非负整数表示第 i 组数据的答案
     
    Sample Input
    1 4 4 1 2 1 2 3 1 3 4 1 4 1 1
     
    Sample Output
    6

    题解:跑堆优化的 Dijkstra(修改过),每个点跑一遍,然后边跑边记录D[i][j]。具体操作看代码。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #pragma GCC optimize(2)
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<set>
    #include<cmath>
    #include<string>
    #include<map>
    #include<vector>
    #include<ctime>
    #include<stack>
    using namespace std;
    #define mm(a,b) memset(a,b,sizeof(a))
    typedef long long ll;
    const long long mod = 998244353;
    const int maxn = 2e3;
     
    int D[maxn][maxn];
    int ans;
    int n,m;
    const ll INF=3e13;
    const int MAXN=5010;
     
    struct qnode
    {
        int v;
        ll c;
        qnode(int _v=0,ll _c=0):v(_v),c(_c){}
        bool operator <(const qnode &r)const
        {
            return c>r.c;
        }
    };
    struct Edge
    {
        int v;
        ll cost;
        Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
    };
     
    vector<Edge>E[MAXN];
    bool vis[MAXN];
    ll dist[MAXN];
    void Dijkstra(int n,int start)//点的编号从1开始
    {
        memset(vis,false,sizeof(vis));
        for(int i=1;i<=n;i++)dist[i]=INF;
        priority_queue<qnode>que;
        while(!que.empty())que.pop();
        dist[start]=0;
        for(int i=0;i<E[start].size();i++)
        {
            que.push(qnode(E[start][i].v,E[start][i].cost));
            dist[E[start][i].v]=min(E[start][i].cost,dist[E[start][i].v]);
        }
        qnode tmp;
        while(!que.empty())
        {
            tmp=que.top();
            que.pop();
            int u=tmp.v;
            if(vis[u]) continue;
            vis[u]=true;
            for(int i=0;i<E[u].size();i++)
            {
                int v=E[u][i].v;
                ll cost=E[u][i].cost;
                if(dist[v]>dist[u]+cost)
                {
                    dist[v]=dist[u]+cost;
                    D[start][v]=max(D[start][u],u);
                    que.push(qnode(v,dist[v]));
                }
                else if(dist[v]==dist[u]+cost)
                {
                    D[start][v]=min(max(u,D[start][u]),D[start][v]);
                }
            }
        }
    }
     
    void addedge(int u,int v,ll w)
    {
        E[u].push_back(Edge(v,w));
    }
     
    void init()
    {
        ans=0;
        for(int i=1;i<=n;i++)
        {
            E[i].clear();
            for(int j=1;j<=n;j++)
            {
                D[i][j]=0;
            }
        }
    }
     
     
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d %d",&n,&m);
            init();
            for(int i=0;i<m;i++)
            {
                int u,v;
                ll W;
                scanf("%d %d %lld",&u,&v,&W);
                addedge(u,v,W);
                addedge(v,u,W);
            }
            for(int i=1;i<=n;i++)
                Dijkstra(n,i);
     
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    //printf("%d ",D[j][i]);
                    ans+=D[i][j];
                    ans%=mod;
                }
                //printf("
    ");
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
     
     
     
     
     
     
  • 相关阅读:
    Linux命令(九)——系统监视和进程控制
    Linux命令(八)——vi编辑器的使用
    Linux命令(七)——网络配置和网络通信
    Linux命令(六)——软件包管理(安装应用程序)
    Linux命令(五)——磁盘操作及文件系统的管理
    Linux命令(四)——文件权限管理
    Linux命令(三)——用户、群组管理命令
    Linux命令(二)——目录和文件管理命令
    mariadb读写分离
    KVM虚拟机热迁移
  • 原文地址:https://www.cnblogs.com/Tangent-1231/p/11406935.html
Copyright © 2011-2022 走看看