P4208 [JSOI2008]最小生成树计数

???这题竟然不是生成树计数?直接暴力就行。我们需要知道一个性质,就是最小生成树无论长成啥样,边权数量是一定的。然后用乘法原理一算就行啦。

好像还有生成树计数的作法,太麻烦了,就不写了。

题干:

题目描述

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

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。

接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。

数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

输出格式:

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

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;++i)
#define lv(i,a,n) for(register int i = a;i >= n;--i)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
const int N = 2010;
const int mod = 31011;
struct node
{
    int l,r,w;
}e[N];
int f[N];
struct rdq
{
    int left,right,va;
}a[N];
int m,n,cnt = 0,ans,sum = 0;
bool cmp(node a,node b)
{
    return a.w < b.w;
}
int find(int x)
{
    if(f[x] == x)
    return x;
    else
    return find(f[x]);
}
void dfs(int x,int now,int k)
{
    if(now == a[x].right + 1)
    {
        if(k == a[x].va)
        {
            sum++;
        }
        return;
    }
    int xx = find(e[now].l),yy = find(e[now].r);
    if(xx != yy)
    {
        f[xx] = yy;
        dfs(x,now + 1,k + 1);
        f[xx] = xx;
        f[yy] = yy;
    }
    dfs(x,now + 1,k);
}
int main()
{
    read(n);read(m);
    duke(i,1,n)
        f[i] = i;
    duke(i,1,m)
    {
        read(e[i].l);read(e[i].r);read(e[i].w);
    }
    sort(e + 1,e + m + 1,cmp);
    int tot = 0;
    for(int i = 1;i <= m;++i)
    {
        if(e[i].w != e[i - 1].w) cnt++,a[cnt].left = i,a[cnt - 1].right = i - 1;
        int xx = find(e[i].l),yy = find(e[i].r);
        if(xx != yy)
        {
            f[xx] = yy;
            a[cnt].va ++;
            tot++;
        }
    }
    if(tot != n - 1)
    {
        printf("0\n");
        return 0;
    }
    a[cnt].right = m;
    ans = 1;
    duke(i,1,n)
    f[i] = i;
    duke(i,1,cnt)
    {
        sum = 0;
        dfs(i,a[i].left,0);
        ans = (ans * sum) % mod;
        for(int j = a[i].left;j <= a[i].right;++j)
        {
            int xx = find(e[j].l),yy = find(e[j].r);
            if(xx != yy)
            {
                f[xx] = yy;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
    
}

 

posted @ 2019-03-12 21:54  DukeLv  阅读(137)  评论(0编辑  收藏  举报