ZOJ - 2316 超详细的题解

Let us consider undirected graph G = which has N vertices and M edges. Incidence matrix of this graph is N * M matrix A = {a ij}, such that a ij is 1 if i-th vertex is one of the ends of j-th edge and 0 in the other case. Your task is to find the sum of all elements of the matrix A TA.

 

This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.

 

Input

 

The first line of the input file contains two integer numbers - N and M (2 <= N <= 10 000, 1 <= M <= 100 000). 2M integer numbers follow, forming M pairs, each pair describes one edge of the graph. All edges are different and there are no loops (i.e. edge ends are distinct).

 

Output

 

Output the only number - the sum requested.

 

Sample Input

 

1

4 4
1 2
1 3
2 3
2 4

 

Sample Output

 

18

题目链接:

ZOJ - 2316

题意:

给定一个有N个顶点,M条边的图,N* M的矩阵A中的元素a(i,j)为1当且仅当第i个顶点是第j条边的端点,否则为0。求AT*A的各个元素之和。AT为A的转置矩阵(M*N)。(2 <= N <= 10000 , 1 <= M <= 100000)(来自nocow)

题解:

Your task is to find the sum of all elements of the matrix A TA.

这道题要求的是所有元素的元素和!!!我竟然,竟然理解错题意了。

首先呢,我们知道,这道题表示的是一个无向图,也就是说联通1、2就相当于联通了2 、1,既然如此的话,在矩阵中不就应该是aij=aji吗,因为矩阵的逆矩阵刚好跟这个相符,那么这道题中,原矩阵跟它的逆矩阵是一样的。

a11 a12 a13                                                    a11*(a11+a21+a31)   

a21 a22 a23           ->求得的ATA等于                                                             (此处省略好多)

a31 a32 a33

 

就观察最后式子的第一个元素就能发现,对于a11,如果说这一点是1的话,那么如果说括号内的元素有1的话,最后的结果就加1.

然而很不幸,a11是0,所以整体都是0

那么如果说现在是a12*(a11+a12+a13)呢?

因为a12是1,也就意味着1和2之间连通了,那么因为a12,a13为1,那么最后就应该加2.

说到这里不知道你发现了没有,我们的最后的结果加1的情况就是下面这样的:

举个例子:a12和a13之间都联通了,那么最后结果加1.

不过我们还可以进行一个转化,也就是说,既然我们知道两个连通了就加1,那么问题就可以转化为找到一个节点已经连通的个数,那么问题来了?我们该怎么找?

可以转化一个思想:就是说我们现在输入了两个节点,那么不就意味着这两个节点都多了一个边了吗?

这样找到每一个节点出现的次数以后,求它们的平方和就行了!

 

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=100005;
int num[maxn];
int main()
{
    int T;
    while(~scanf("%d",&T))
    {
        while(T--)
        {
            int num_max=0;
            memset(num,0,sizeof(num));
            int n,m;
            cin>>n>>m;
            for(int i=1; i<=m; ++i)
            {
                int a,b;
                cin>>a>>b;
                num[a]++;
                num[b]++;
                num_max=max(num_max,max(a,b));
            }
            long long num_puts=0;
            for(int i=0; i<=num_max; ++i)
            {
                num_puts+=(long long)(num[i])*num[i];
            }
            printf("%lld\n",num_puts);
            if(T)
                printf("\n");
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值