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

BZOJ 1016: [JSOI2008]最小生成树计数

时间:2015-05-18 10:55:18      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:


最小生成树计数:

最小生成树的两个性质: 

1.不同的最小生成树中,每种边出现的个数是确定的

2.不同的生成树中,某一种边连接完成后,形成的联通块状态是一样的


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

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 3394  Solved: 1341
[Submit][Status][Discuss]

Description

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

Input

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

Output

输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

Sample Input

4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1

Sample Output

8

HINT

Source

[Submit][Status][Discuss]



/* ***********************************************
Author        :CKboss
Created Time  :2015年05月17日 星期日 09时44分48秒
File Name     :BZOJ1016.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

typedef long long int LL;

const LL maxn=1100;
const LL mod=31011;

LL n,m;
struct Edge
{
	LL u,v,len;
}edge[maxn];
bool cmp(Edge a,Edge b) { return a.len<b.len; }

LL q; LL a[maxn]; LL num[maxn]; 

LL fa[110];

void init()
{
	for(LL i=0;i<110;i++) fa[i]=i;
}

LL find(LL u)
{
	if(u==fa[u]) return u;
	return fa[u]=find(fa[u]);
}

void kruskal()
{
	for(LL i=0;i<m;i++)
	{
		LL u=find(edge[i].u);
		LL v=find(edge[i].v);
		LL len=edge[i].len;

		if(u==v) continue;
		else
		{
			fa[u]=v;
			if(a[q]!=len) a[++q]=len;
			num[q]++;
		}
	}
}

LL find2(LL x)
{
	if(x==fa[x]) return x;
	return find2(fa[x]);
}


LL part[maxn];

void dfs(LL id,LL from,LL to,LL num)
{
	if(num==0) { part[id]++; if(part[id]>=mod) part[id]-=mod; return ; }
	for(LL i=from;i<=to;i++)
	{
		LL u=find2(edge[i].u);
		LL v=find2(edge[i].v);
		if(u==v) continue;
		else
		{
			LL t=fa[u];
			fa[u]=v;
			dfs(id,i+1,to,num-1);
			fa[u]=t;
		}
	}
}

bool flag;
void Link(LL id,LL from,LL to,LL num)
{
	if(flag) return ;
	if(num==0) { flag=true; return ; }

	for(LL i=from;i<=to&&flag==false;i++)
	{
		LL u=find2(edge[i].u);
		LL v=find2(edge[i].v);
		if(u==v) continue;
		else
		{
			LL t=fa[u];
			fa[u]=v;
			Link(id,i+1,to,num-1);
			if(flag) return ;
			fa[u]=t;
		}
	}
}

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);

	init();
	scanf("%lld%lld",&n,&m);
	for(LL i=0,u,v,w;i<m;i++)
	{
		scanf("%lld%lld%lld",&u,&v,&w);
		edge[i]=(Edge){u,v,w};
	}
	sort(edge,edge+m,cmp);

	kruskal();

	int go=find(1);
	for(int i=2;i<=n;i++)
	{
		if(go==find(i)) continue;
		else { go=-1; break; }
	}

	if(go==-1)
	{
		puts("0"); return 0;
	}
    
	init();
	LL from=0,to=0;
	for(LL i=1;i<=q;i++)
	{
		for(LL j=from;j<m;j++)
			if(edge[j].len==a[i]) to=j;

		dfs(i,from,to,num[i]);
		flag=false;

		Link(i,from,to,num[i]);
		from=to+1;
	}

	LL ans=part[1]%mod;
	for(LL i=2;i<=q;i++)
	{
		ans*=part[i];
		ans%=mod;
	}

	printf("%lld\n",ans%mod);

    return 0;
}



BZOJ 1016: [JSOI2008]最小生成树计数

标签:

原文地址:http://blog.csdn.net/ck_boss/article/details/45815651

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