bzoj1016: [JSOI2008]最小生成树计数

题目链接

bzoj1016

题目描述

Description

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。

Input

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

Output

输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

Sample Input

4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1

Sample Output

8

题解

在所有的最小生成树中相同权值的边选的个数都是一样的,并且互不干扰。
我们可以对每一种相同权值的边都搜一下有多少种不同的选择,乘起来就是答案。这题保证了相同权值的边不超过10,所有搜索是不会超时的。
如果相同权值的边再多一些,可以用行列式来做。可以参考http://www.cnblogs.com/Fatedayt/archive/2012/05/10/2494877.html


#include<cstdio>
#include<algorithm>
using namespace std;
struct edge{
    int x,y,data;
    friend bool operator <(edge a,edge b){
        return a.data<b.data;
    }
}e[1010];
struct node{
    int data,num,size;
}c[1010];
int f[110],cnt,tot,n,m,ans,sum;
int get(int x){return f[x]==x?x:get(f[x]);}
bool combine(int x,int y){
    x=get(x); y=get(y);
    if(x==y) return false;
    f[x]=y; return true;
}
void dfs(int x,int y,int k,int now){
    if(x>y){
        if(k==now) sum++;
        return;
    }
    int p=get(e[x].x),q=get(e[x].y);
    if(p!=q){
        f[p]=q;
        dfs(x+1,y,k,now+1);
        f[p]=p;
    }
    dfs(x+1,y,k,now);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) 
    scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].data);
    sort(e+1,e+1+m);
    e[m+1].data=-1;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++){
        if(combine(e[i].x,e[i].y)) cnt++,ans++;
        if(e[i].data!=e[i+1].data){
            c[++tot].data=e[i].data;
            c[tot].num=cnt;
            c[tot].size=i;
            cnt=0;
        }
    }
    ans=ans==n-1;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=tot;i++){
        sum=0;
        dfs(c[i-1].size+1,c[i].size,c[i].num,0);
        ans=(long long)ans*sum%31011;
        for(int j=c[i-1].size+1;j<=c[i].size;j++) 
        combine(e[j].x,e[j].y);
    }
    printf("%d\n",ans);
    return 0;
}
发布了60 篇原创文章 · 获赞 8 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章