BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索

Posted yxysuanfa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索相关的知识,希望对你有一定的参考价值。

题目大意:给出一些边,求出一共能形成多少个最小生成树。


思路:最小生成树有非常多定理啊,我也不是非常明确。这里仅仅简单讲讲做法。关于定各种定理请看这里:http://blog.csdn.net/wyfcyx_forever/article/details/40182739

我们先做一次最小生成树。然后记录每一种长度的边有多少在最小生成树中,然后从小到大搜索,看每一种边权有多少种放法。然后全部的都算出来累乘就是终于的结果。


CODE:

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 2010
#define MO 31011
using namespace std;

map<int,int> G;

struct Complex{
	int x,y,len;

	bool operator <(const Complex &a)const {
		return len < a.len;
	}
	void Read() {
		scanf("%d%d%d",&x,&y,&len);
	}
}edge[MAX];

int points,edges;
int ones[MAX];

int father[MAX];
int ans = 1;

void Pretreatment()
{
	for(int i = 1;i <= 1025; ++i)
		ones[i] = ones[i >> 1] + (i&1);
}

int Find(int x)
{
	if(!father[x] || father[x] == x)	return father[x] = x;
	return father[x] = Find(father[x]);
}

bool Kruskal()
{
	int cnt = 0;
	for(int i = 1;i <= edges; ++i) {
		int fx = Find(edge[i].x);
		int fy = Find(edge[i].y);
		if(fx != fy) {
			father[fy] = fx;
			G[edge[i].len]++;
			cnt++;
		}
	}
	if(cnt < points - 1)	return false;
	return true;
}

void DFS(int pos)
{
	if(pos > edges)	return ;
	int st = pos,ed = pos,re = 0;
	int cnt = G[edge[st].len];
	if(!cnt) {
		DFS(ed + 1);
		return ;
	}
	while(edge[ed + 1].len == edge[st].len)	++ed;
	for(int i = 0;i < (1 << (ed - st + 1)); ++i)
		if(ones[i] == cnt) {
			memset(father,0,sizeof(father));
			int temp = i;
			for(int j = st; temp; temp >>= 1,++j)
				if(temp&1) {
					int fx = Find(edge[j].x);
					int fy = Find(edge[j].y);
					if(fx == fy)	break;
					father[fy] = fx;
				}
			if(!temp)	++re;
		}
	ans = (ans * re) % MO;
	memset(father,0,sizeof(father));
	for(int i = st; i <= ed; ++i) {
		int fx = Find(edge[i].x);
		int fy = Find(edge[i].y);
		if(fx == fy)	continue;
		father[fy] = fx;
	}
	for(int i = ed + 1;i <= edges; ++i)
		edge[i].x = Find(edge[i].x),edge[i].y = Find(edge[i].y);
	DFS(ed + 1);
}

int main()
{
	Pretreatment();
	cin >> points >> edges;
	for(int i = 1;i <= edges; ++i)
		edge[i].Read();
	sort(edge + 1,edge + edges + 1);
	memset(father,0,sizeof(father));
	if(!Kruskal()) {
		cout << 0 << endl;
		return 0;
	}
	DFS(1);
	cout << ans << endl;
	return 0;
}








以上是关于BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1016 [JSOI2008]最小生成树计数

BZOJ-1016: [JSOI2008]最小生成树计数 (kruscal+搜索)

bzoj1016: [JSOI2008]最小生成树计数

BZOJ1016:[JSOI2008]最小生成树计数——题解

BZOJ1016: [JSOI2008]最小生成树计数 深搜+并查集

bzoj1016[JSOI2008]最小生成树计数