BZOJ1016 JSOI2008最小生成树计数

定理,在所有最小生成树中,相同边权的边出现的次数相同。

由于重复边权小于10条,可以跑2^10暴力

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10,mod=31011;
struct node{
    int x,y,w;
    bool operator <(const node &b)const{
        return w<b.w;
    }
}e[N];
struct poin{
    int l,r,v;
}a[N];
int n,m,sum,ans=1,f[N],cnt;
inline int get(int x){return x==f[x]?x:get(f[x]);}
void dfs(int x,int now,int num)
{
    if(num==a[x].v){
        sum++;return;
    }
    if(now>a[x].r)return;
    int fx=get(e[now].x),fy=get(e[now].y);
    if(fx!=fy){
        f[fx]=fy;dfs(x,now+1,num+1);
        f[fx]=fx;f[fy]=fy;
    }
    dfs(x,now+1,num);
}
inline int read()
{
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;++i)
    {
        e[i].x=read();e[i].y=read();e[i].w=read();
    }
    sort(e+1,e+1+m);
    for(int i=1;i<=n;++i)f[i]=i;int num=0;
    for(int i=1;i<=m;++i)
    {
        if(e[i].w!=e[i-1].w)a[++cnt].l=i,a[cnt-1].r=i-1;
        int fx=get(e[i].x),fy=get(e[i].y);
        if(fx!=fy)
        {
            f[fx]=fy;a[cnt].v++;num++;
        }
    }
    if(num!=n-1){puts("0");return 0;}
    a[cnt].r=m;for(int i=1;i<=n;++i)f[i]=i;
    for(int i=1;i<=cnt;++i)
    {
        sum=0;
        dfs(i,a[i].l,0);
        ans=1ll*ans*sum%mod;
        for(int j=a[i].l;j<=a[i].r;++j)
        {
            int fx=get(e[j].x),fy=get(e[j].y);
            if(fx!=fy)f[fx]=fy;
        }
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-01-16 19:28  大奕哥&VANE  阅读(...)  评论(... 编辑 收藏