[BZOJ5297][CQOI2018]社交网络(Matrix-Tree定理)

5297: [Cqoi2018]社交网络

Time Limit: 20 Sec   Memory Limit: 512 MB
Submit: 20   Solved: 13
[ Submit][ Status][ Discuss]

Description

当今社会,在社交网络上看朋友的消息已经成为许多人生活的一部分。通常,一个用户在社交网络上发布一条消息(例如微博、状态、Tweet等)后,他的好友们也可以看见这条消息,并可能转发。转发的消息还可以继续被人转发,进而扩散到整个社交网络中。在一个实验性的小规模社交网络中我们发现,有时一条热门消息最终会被所有人转发。为了研究这一现象发生的过程,我们希望计算一条消息所有可能的转发途径有多少种。为了编程方便,我们将初始消息发送者编号为1,其他用户编号依次递增。该社交网络上的所有好友关系是已知的,也就是说对于A、B两个用户,我们知道A用户可以看到B用户发送的消息。注意可能存在单向的好友关系,即A能看到B的消息,但B不能看到A的消息。还有一个假设是,如果某用户看到他的多个好友转发了同一条消息,他只会选择从其中一个转发,最多转发一次消息。从不同好友的转发,被视为不同的情况如果用箭头表示好友关系,下图展示了某个社交网络中消息转发的所有可能情况。

这里写图片描述

初始消息是用户1发送的,加粗箭头表示一次消息转发

Input

输入文件第一行,为一个正整数n,表示社交网络中的用户数:
第二行为一个正整数m.表示社交网络中的好友关系数目。
接下来m行,每行为两个空格分隔的整数ai和bi,表示一组好友关系,即用户ai可以看到用户bi发送的消息。
1≤n≤250,1≤ai,bi≤n,1≤m≤n(n-1)

Output

输出文件共一行,为一条消息所有可能的转发途径的数量,除以1 0007所得的余数。

Sample Input

4
7
2 1
3 1
1 3
2 3
3 2
4 3
4 2

Sample Output

6

思路&&分析

    这题就是给你一个有向图,让你找出以节点1为根的有根树有多少颗。注意输入中的u,v和我们平常的u,v是相反的。
    我们将题意转化了之后,就可以很显然的看出这是一个Matrix-Tree定理的题,我们只要根据图建出一个拉普拉斯矩阵,之后再求一下行列式,就可以得出答案了。

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=255,mod=10007;
int n,m,val[maxn][maxn];
int main() {
    read(n),read(m);
    for(int i=1,u,v;i<=m;i++) {
        read(v),read(u);v--,u--;
        if(u&&v)
            val[u][v]--;
        if(v)
            val[v][v]++;
    }
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            val[i][j]=(val[i][j]%mod+mod)%mod;
    int sgn=1;
    for(int i=1;i<n;i++)
        for(int j=i+1;j<n;j++) {
            while(1) {
                if(!val[j][i])
                    break;
                int x=val[i][i]/val[j][i];
                for(int k=1;k<n;k++)
                    val[i][k]=(val[i][k]-val[j][k]*x%mod+mod)%mod;
                for(int k=1;k<n;k++)
                    swap(val[i][k],val[j][k]);
                sgn*=-1;
            }
        }
    int ans=1;
    for(int i=1;i<n;i++)
        ans=ans*val[i][i]%mod;
    ans=(ans*sgn%mod+mod)%mod;
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/effervescence/article/details/79979549