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

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

时间:2014-10-22 15:55:16      阅读:306      评论:0      收藏:0      [点我收藏+]

标签:bzoj   jsoi2008   最小生成树   搜索   

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


思路:最小生成树有很多定理啊,我也不是很明白,这里只简单讲讲做法,关于定各种定理请看这里: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   jsoi2008   最小生成树   搜索   

原文地址:http://blog.csdn.net/jiangyuze831/article/details/40377247

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