bzoj1016: [JSOI2008]最小生成树计数
题目链接
题解
每种权值的边的数量是确定的,每种权值的边的作用是确定的
求一遍最小生成树,对于相同权值的边分组
然后对于每一种权值的边搜索,得出每组权值的边选择方案
乘法原理统计答案
代码
#include<cstdio>
#include<algorithm>
inline int read() {
int x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();}
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
return x * f;
}
const int maxn = 1007;
struct Edge{int u,v,w;
bool operator < (const Edge &a)const {
return w < a.w;
}
}edge[maxn];
#define mod 31011
struct Data {
int l,r,v;
}a[maxn];
int fa[maxn],n,ans = 1,sum = 0,m;
int find(int x) { if(fa[x] != x) return find(fa[x]);else return x; }
void dfs(int x,int now,int k) {
if(now == a[x].r + 1) {
if(k == a[x].v) sum ++;
return ;
}
int p = find(edge[now].u),q = find(edge[now].v);
if(p != q) {
fa[p] = q;
dfs(x,now + 1,k + 1);
fa[p] = p;fa[q] = q;
}
dfs(x,now + 1,k);
}
int main() {
n = read(),m = read();
for(int i = 1;i <= m;++ i) {
edge[i].u = read();
edge[i].v = read();
edge[i].w = read();fa[i] = i;
}
int cnt = 0,tot = 0;
std::sort(edge + 1,edge + m + 1);
for(int i = 1;i <= m;++ i) {
if(edge[i].w != edge[i - 1].w) a[cnt].r = i - 1,a[++cnt].l = i;
int p = find(edge[i].u),q = find(edge[i].v);
if(p != q) {fa[p] = q;a[cnt].v++;tot++; }
}
a[cnt].r = m;
if(tot != n - 1)puts("0");
else {
for(int i = 1;i <= n;++ i) fa[i] = i;
for(int i = 1;i <= cnt;++ i) {
sum = 0;
dfs(i,a[i].l,0);
ans = ans * sum % mod;
for(int j = a[i].l;j <= a[i].r;++ j) {
int p = find(edge[j].u),q = find(edge[j].v);
if(p != q) fa[p] = q;
}
}
printf("%d\n",ans);
}
return 0;
}