码迷,mamicode.com
首页 > Web开发 > 详细

P4208 [JSOI2008]最小生成树计数

时间:2020-05-26 18:43:17      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:答案   cpp   for   ==   计数   char   dfs   read   print   

题目描述

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

题解

容易想到对于边权相同的那些边,选出来的边数是一定的,所以最终答案其实就是各个边权相同的部分的方案数的乘积,用并查集维护\(dfs\)即可,注意:由于有撤销操作,所以不能进行路径压缩。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1005;
const int mod = 31011;
int n, m, fa[N], cnt, tot, sum, ans = 1, now;
struct node{int x, y, z;}a[N];
struct data{int l, r, val;}e[N];
inline int read()
{
	int x = 0, f = 1; char ch = getchar();
	while(ch < ‘0‘ || ch > ‘9‘) {if(ch == ‘-‘) f = -1; ch = getchar();}
	while(ch >= ‘0‘ && ch <= ‘9‘) {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
bool cmp(const node & a, const node & b) {return a.z < b.z;}
int find(int x) {return fa[x] == x ? x : find(fa[x]);}
void dfs(int x, int goal, int num)
{
	if(x == goal + 1) {if(num == now) sum ++; return;}
	int xx = find(a[x].x), yy = find(a[x].y);
	if(xx != yy)
	{
		fa[xx] = yy; dfs(x + 1, goal, num + 1);
		fa[xx] = xx; fa[yy] = yy;
	}
	dfs(x + 1, goal, num);
}
int main()
{
//	freopen("a.in", "r", stdin);
//	freopen("a.out", "w", stdout);
	n = read(); m = read();
	for(int i = 1; i <= n; i ++) fa[i] = i;
	for(int i = 1; i <= m; i ++) a[i].x = read(), a[i].y = read(), a[i].z = read();
	sort(a + 1, a + m + 1, cmp);
	for(int i = 1; i <= m; i ++)
	{
		if(a[i].z != a[i - 1].z) cnt ++, e[cnt].l = i, e[cnt - 1].r = i - 1;
		int x = find(a[i].x), y = find(a[i].y);
		if(x != y) {fa[x] = y; tot ++; e[cnt].val ++;}
	}
	e[cnt].r = m; if(tot != n - 1) {printf("0\n"); return 0;}
	for(int i = 1; i <= n; i ++) fa[i] = i;
	for(int i = 1; i <= cnt; i ++)
	{
		sum = 0; now = e[i].val; dfs(e[i].l, e[i].r, 0); ans = (ans * sum) % mod;
		for(int j = e[i].l; j <= e[i].r; j ++)
		{
			int x = find(a[j].x), y = find(a[j].y);
			if(x != y) fa[x] = y;
		}
	}
	printf("%d\n", ans);
	return 0;
}

P4208 [JSOI2008]最小生成树计数

标签:答案   cpp   for   ==   计数   char   dfs   read   print   

原文地址:https://www.cnblogs.com/Sunny-r/p/12966803.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!