【CQOI2018】【矩阵树定理】社交网络

【描述】
当今社会,在社交网络上看朋友的消息已经成为许多人生活的一部分。通常,一个用户在社交网络上发布一条消息(例如微博、状态、Tweet等)后,他的好友们也可以看见这条消息,并可能转发。转发的消息还可以继续被人转发,进而扩散到整个社交网络中。在一个实验性的小规模社交网络中我们发现,有时一条热门消息最终会被所有人转发。为了研究这一现象发生的过程,我们希望计算一条消息所有可能的转发途径有多少种。为了编程方便,我们将初始消息发送者编号为1,其他用户编号依次递增。该社交网络上的所有好友关系是已知的,也就是说对于A、B两个用户,我们知道A用户可以看到B用户发送的消息。注意可能存在单向的好友关系,即A能看到B的消息,但B不能看到A的消息。
还有一个假设是,如果某用户看到他的多个好友转发了同一条消息,他只会选择从其中一个转发,最多转发一次消息。从不同好友的转发,被视为不同的情况。
如果用箭头表示好友关系,下图展示了某个社交网络中消息转发的所有可能情况。
在这里插入图片描述
初始消息是用户1发送的,加粗箭头表示一次消息转发
【输入】
输入文件第一行,为一个正整数n,表示社交网络中的用户数:
第二行为一个正整数m.表示社交网络中的好友关系数目。
接下来m行,每行为两个空格分隔的整数ai和bi,表示一组好友关系,即用户ai可以看到用户bi发送的消息。
【输出】
输出文件共一行,为一条消息所有可能的转发途径的数量,除以10007所得的余数。

【思路】

Matrix-Tree有向图外向生成树计数:度数矩阵记录入度,邻接矩阵记录出边连边情况。此时基尔霍夫矩阵去掉第i列i行的主余子式的行列式代表以i为根的生成树个数。内向树计数类似。

#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=255;
const int mod=10007;
int n,m,a,b,c;
inline int red()
{
    int data=0;int w=1; char ch=0;
    ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
int cnt=0;
struct mat{
	int f[N][N];
	int gauss(){
		int ans=1;
		for(int re i=2;i<=n;i++){
			for(int re j=i+1;j<=n;j++)
				while(f[j][i]){
					int t=f[i][i]/f[j][i];
					for(int re k=i;k<=n;k++)
						f[i][k]=((f[i][k]-t*f[j][k])%mod+mod)%mod;
					swap(f[i],f[j]);
					ans=-ans;
				}ans=(ans*f[i][i])%mod;
		}return (ans+mod)%mod;
	}
}A;
inline void add(int a,int b){A.f[a][b]--;A.f[b][b]++;}
char s[N];
int main()
{
	n=red();m=red();
	for(int re i=1;i<=m;i++)add(red(),red());
	cout<<A.gauss();
}
发布了106 篇原创文章 · 获赞 22 · 访问量 5491

猜你喜欢

转载自blog.csdn.net/weixin_44111457/article/details/102023633
今日推荐