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 */