您的位置:首页 > Web前端 > JavaScript

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

2015-05-18 10:11 477 查看
最小生成树计数:

最小生成树的两个性质: 

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: