牛客网暑期ACM多校训练营(第十场) F - Rikka with Line Graph 图论 弗洛伊德+思维

100 篇文章 0 订阅

链接:https://www.nowcoder.com/acm/contest/148/F
来源:牛客网
 

Rikka with Line Graph

时间限制:C/C++ 10秒,其他语言20秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

Line Graph L(G) can be considered as an operator on an undirected graph G just like Complementary Graph and Dual Graph.

Rikka generalizes Line Graph to edge-weighted undirected graphs. For a graph , L(G) is still an edge-weighted undirected graph which is constructed in the following way:
1. L(G) has |E| vertices and the ith vertex corresponds to the ith edge in G.
2. There is an edge between i,j in L(G) if and only if edge i and j have at least one common vertices in G. And the edge weight is equal to the sum of the weights of edge i and j in G.

For example, in the following picture, the right graph is the line graph of the left one. Vertex 1,2,3,4 in L(G) correspond to edge (1,2),(1,4),(1,3),(3,4) in G. And if all edges in the left graph have weight 1, the edges in the right graph will have weight 2.


Now, Rikka has an edge-weighted undirected complete graph G with n vertices. And she constructs a graph G'=L(G). It is clear that G' is connected.

Let d(i,j) be the length of the shortest path between vertex i,j in G'(the length of each edge is equal to its weight), K be the number of vertices in G', Rikka wants you to calculate .

输入描述:

The first line contains a single number t(1 ≤ t ≤ 3), the number of the testcases.

For each testcase, the first line contains one single integer n(2 ≤ n ≤ 500). 

Then n lines follow, each line contains n integers wi,j(0 ≤ wi,j ≤ 109), the weight of each edge in G. Since there are no self circles in G, the value of wi,i is meaningless.

The input guarantees that for all 1 ≤ i ≠ j ≤ n, wi,i=0 and wi,j = wj,i.

输出描述:

For each testcase, output a single line with a single number, the answer modulo 998244353.

示例1

输入

3
2
0 1
1 0
3
0 1 1
1 0 1
1 1 0
4
0 1 1 1
1 0 2 2
1 2 0 3
1 2 3 0

输出

0
6
56

题意:

    先给你一个无向图的矩阵,矩阵a的数值a[i][j]代表点i到点j的边。

    为了求这个图的线图现在要对这个无向图如下的变换:

    1.它的点集大小为|E|,每个点对应着这个这个图的唯一一条边。(即原图中的每条边都变成了一个点)

    2.两个点有边当且仅当这两个点对应的边在原图中有公共点,(即如果点1 2之间有边 点2 3之间有边,那么在线图中的点[1][2]和点[2][3]之间会有一条边),在线图中这条边的权值为“在原图中这两条边的权值和”。

    现在要你求在线图中任意两个点之间的最短路的和,即\sum _{i=1}^{n}\sum _{j=i+1}^{n} dis(i,j)

 

做法:

       我们手模一下线图中的一条路径,我们会发现,在计算距离的时候时,这一整条路径上,两端的边的权值被算了一次,中间的被算了两次。

    直觉告诉我们!两端的边的权值一定会被算一次,中间的边我们需要另外计算。

  因为每条边都会和其他(n-1)*n/2条边配对,至少被加(n-1)*n/2次,所以可以直接先加上。

       dis(a,b)_{ in L(G)}=edgeval_{a}+edgeval_{b}+2*dis(a',b')_{in (G)}

  对于中间的距离,即dis(a',b')这个a',b'分别指把路径还原后,除掉两端点,剩下的两个端点的节点编号。为了使这个距离最小,再加上这个10s的时间,我们可以让边可以选择其的任意一个端点a’,b选择其任意一个端点b’,用Floyd 预处理最短路,在这4种情况下取最小值,来方便的计算线图上任意两个点的距离。

       我们用一个图来进行表示接下来的过程

       

       我们可以把一条路径上的边重复加两次转换成对一个边处理时加一次,这样一条路上的起点边和终点边都各加一次就会变成两次 。我们对于这样一个图,假设从点A B边开始,用a数组记录这条边到其他点的距离,很明显到点A,B都会是0,通过弗洛伊德之后,到点C的距离变成2,distoD=1,distoE=1  我们可以把这个数组进行排序,得到1 1 3很明显我们会尽量走距离小的边,假设先加点D的1,因为点D连接着C和E,我们就可以用这一个1*2加入答案,这样边AB和边DC以及边DE都可以被计算掉,第二次是点E的1,在第一次处理后只剩下一个点,那么我们就用1*1加入答案,只需要枚举n-2次即可。  然后就是每一条边的枚举。

  这样,Floyd是O(n^{3})的;枚举一条边是O(n^{2})的,得到边后的处理是O(n)的,所以总复杂度也是O(n^{3})的。

  最终时间复杂度O(n^{3}) 。

 

      网上没有多少题解。。只能对着大神的代码啃。。花了好久。。还是太菜了唉。。。

 

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=505;
ll mp[maxn][maxn],d[maxn][maxn],n,ans,a[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        ans=0;
        scanf("%lld",&n);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%lld",&d[i][j]);
                if(i==j) d[i][j]=0;
             }
        }
        ll bian=(n-1)*n/2-1;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                ans=(ans+bian*d[i][j]%mod)%mod;
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(k!=i&&k!=j&&i!=j) d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                for(int k=1;k<=n;k++)
                    a[k]=min(d[i][k],d[j][k]);
                sort(a+1,a+1+n);
                for(int k=1;k<n;k++){
                    ans=(ans+(ll)(n-k)*a[k]%mod)%mod;
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值