[JSOI2008]最小生成树计数

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,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过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

Solution

这题目,鬼畜至极。。。看了题解,又发现是矩阵树。。然后经过非常合理的判断,这个题目有一个非常友好的性质——具有相同权值的边不会超过10条。这样就使暴力搜索这种做法成为了可能的做法。

YY一下, 我们可以知道对于我们已经求出的一棵最小生成树,其中每种权值的边的数量就已经是确定的了。那么我们枚举每一种权值的边,判断它有几种方案可行即可。又由于刚才那个美妙的性质,我们每一种边权的最大枚举次数最多是1024。

Code

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#define re register
#define mo 31011
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(arr) memset(arr, 0, sizeof(arr))
const int inf = 0x3f3f3f3f;
struct po
{
    int x,y,l;
};
po a[1010];
struct tt
{
    int l,r,v;
} p[1010];
int n,m,t,cnt,num,f[1001],sum,tot;
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    while(ch=='-') c*=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
inline bool cmp(po a,po b)
{
    return a.l<b.l;
}
inline int find(int x)
{
    return x==f[x]?x:find(f[x]);
}
void dfs(int x,int now,int k)
{
    if(now==p[x].r+1){
        if(k==p[x].v) sum++;
        return;
    }
    int r1=find(a[now].x),r2=find(a[now].y);
    if(r1!=r2){
        f[r1]=r2;
        dfs(x,now+1,k+1);
        f[r1]=r1;f[r2]=r2;
    }
    dfs(x,now+1,k);
}
int main() 
{
    n=read();m=read();
    for(re int i=1;i<=m;i++)
        a[i].x=read(),a[i].y=read(),a[i].l=read();
    for(re int i=1;i<=n;i++) f[i]=i;
    sort(a+1,a+m+1,cmp);
    for(re int i=1;i<=m;i++){
        if(a[i].l!=a[i-1].l) cnt++,p[cnt].l=i,p[cnt-1].r=i-1;
        int r1=find(a[i].x),r2=find(a[i].y);
        if(r1!=r2) f[r1]=r2,p[cnt].v++,tot++;
    }
    if(tot!=n-1) {
        cout<<0;
        return 0;
    }
    p[cnt].r=m;
    int ans=1;
    for(re int i=1;i<=n;i++) f[i]=i;
    for(re int i=1;i<=cnt;i++){
        sum=0;
        dfs(i,p[i].l,0);
        ans=(ans*sum)%mo;
        for(re int j=p[i].l;j<=p[i].r;j++){
            int r1=find(a[j].x),r2=find(a[j].y);
            if(r1!=r2) f[r1]=r2;
        }
    }
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/victorique/p/9175013.html