BZOJ 1016 最小生成树计数 Kruskal

来源:互联网 发布:linux dhcp安装包下载 编辑:程序博客网 时间:2024/05/17 06:55

题目

给出一个简单无向加权图,求最小生成树有多少种?

分析

首先最小生成树有以下两个性质:
(1)每种权值相同的边的数量是一定的。
(2)权值相同的边对最小生成树的效果相同。

那么首先求一次最小生成树,找出每种边的数量。
然后枚举权值,可以进行搜索或者用Matrix-Tree定理用行列式进行生成树计数。
根据乘法原理相乘即结果。

代码

#include <bits/stdc++.h>using namespace std;const int N=128;const int M=1024;const int MOD=31011;int n,m;int f[N];struct Edge{    int u,v,d;}e[M];struct List{    int id;    int nxt;}ud_list[M];int hd[M],tt,num;int cnt[M];int res=1,sum;inline int Read(void){    int s=0,f=1; char c=getchar();    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;    for (;isdigit(c);c=getchar()) s=s*10+c-'0';    return s*f;}inline int operator < (Edge ea,Edge eb){    return ea.d<eb.d;}inline void InsList(int w,int id){    ud_list[++tt].id=id;    ud_list[tt].nxt=hd[w];    hd[w]=tt;}int Find(int i){    return f[i]==i?i:Find(f[i]);}void DFS(int k,int dep,int goal){    if (dep==goal) {sum++;return;}    if (!k) return;    int fu=Find(e[ud_list[k].id].u),fv=Find(e[ud_list[k].id].v);    if (fu!=fv)    {        f[fu]=fv;        DFS(ud_list[k].nxt,dep+1,goal);        f[fu]=fu,f[fv]=fv;    }    DFS(ud_list[k].nxt,dep,goal);}int main(void){       n=Read(),m=Read();    for (int i=1;i<=m;i++) e[i].u=Read(),e[i].v=Read(),e[i].d=Read();    int tmp=0;    sort(e+1,e+m+1);    for (int i=1;i<=m;i++)    {        if (e[i].d!=tmp) num++;        tmp=e[i].d;        e[i].d=num;        InsList(num,i);    }    int fu,fv,totc=0;    for (int i=1;i<=n;i++) f[i]=i;    for (int i=1;i<=m;i++)    {        fu=Find(e[i].u),fv=Find(e[i].v);        if (fu==fv) continue;        cnt[e[i].d]++,totc++,f[fu]=fv;    }    if (totc!=n-1) {printf("0\n");return 0;}    for (int i=1;i<=n;i++) f[i]=i;    for (int i=1;i<=num;i++)    {        sum=0; DFS(hd[i],0,cnt[i]);        res=res*sum%MOD;        for (int k=hd[i];k;k=ud_list[k].nxt)        {            fu=Find(e[ud_list[k].id].u),fv=Find(e[ud_list[k].id].v);            if (fu!=fv) f[fu]=fv;        }    }    printf("%d\n",res);    return 0;}
0 0
原创粉丝点击