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; }
只想找一个不会伤害我的人