BZOJ 1016 [JSOI2008]最小生成树计数(kruskal + dfs)

题意:

求最小生成树的个数

思路:

网上很多题解都是矩阵树,

由克鲁斯卡尔的步骤可以知道mst的每一种边权选的条数是固定的,所以我们dfs具体每种权值选哪几条并不会成环的方案数,相乘即可

dfs是参考网上的,我是不会的


代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
    
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x)) 

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 998244353;
const int maxn = 2e6+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int fa[1000 + 10];
struct Edge{
    int u, v, w;
}edge[1000 + 10];
struct Node{
    int l ,r, num;
}node[1000 + 10];
int find(int x){
    return fa[x]==x?x:find(fa[x]);
}

bool cmp(Edge a, Edge b){
    return a.w < b.w;
}
int tol;
int n, m;
int cnt = 0;
ll sum = 0;

void init(){
    for(int i = 1; i <= n; i++){
        fa[i] = i;
    }
    return;
}

void dfs(int nodeid, int edgeid, int num){
    if(edgeid > node[nodeid].r){
        if(num==node[nodeid].num)sum++;
        return;
    }
    int u = edge[edgeid].u;
    int v = edge[edgeid].v;
    int t1 = find(u);
    int t2 = find(v);
    if(t1 != t2){
        fa[t1]=t2;
        dfs(nodeid, edgeid+1, num+1);//选这条边
        fa[t1]=t1; //改回去
        fa[t2]=t2;
    }
    dfs(nodeid, edgeid+1, num); //不选这条边
    return;
}

int main(){
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= m; i++){
        scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].w);
    }
    sort(edge + 1, edge + 1 + m, cmp);
    ll ans = 1;
    init();
    tol = 0;
    cnt = 0;
    for(int i = 1; i <= m; i++){
        if(i==1 || edge[i].w != edge[i-1].w){
            node[cnt++].r = i-1;
            node[cnt].l = i;
            node[cnt].num = 0;
        }
        int u = edge[i].u;
        int v = edge[i].v;
        int t1 = find(u);
        int t2 = find(v);
        if(t1 != t2){
            fa[t1] = t2;
            node[cnt].num++;
            tol++;
        }
    }
    node[cnt].r = m;
    if(tol != n-1){
        printf("0");
        return 0;
    }
    init();
    for(int i = 1; i <= cnt; i++){
        sum = 0;
        dfs(i, node[i].l, 0);
        ans*=sum;
        ans%=31011;

        //最后是改回去的,所以得把这个权值的连回来
        for(int j = node[i].l; j <= node[i].r; j++){
            int u = edge[j].u;
            int v = edge[j].v;
            int t1 = find(u);
            int t2 = find(v);
            if(t1 != t2){
                fa[t1] = t2;
            }
        }
    }
    printf("%lld\n", ans);
    return 0;

}
/*
10
1 3 5 -1 5 7 -5 9 -1 1

9
2 3 5 2 1 6 4 2 3
 */

 

posted @ 2018-10-22 21:44  wrjlinkkkkkk  阅读(178)  评论(0编辑  收藏  举报