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

BZOJ 题目1016: [JSOI2008]最小生成树计数(Kruskal+Matrix_Tree)

2015-08-12 20:38 686 查看

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

Time Limit: 1 Sec Memory Limit: 162 MB

Submit: 3569 Solved: 1425

[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]


HOME Back

感觉这个oj还是很好用的,而且题也不错,没那么多废话,

调试了很久还是不是能完全的理解,按别人的代码一步步敲了,,a了

ac代码

/**************************************************************
Problem: 1016
User: kxh1995
Language: C++
Result: Accepted
Time:60 ms
Memory:9280 kb
****************************************************************/

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stdlib.h>
#define mod 31011
using namespace std;
struct s
{
int u,v,w;
}edge[1010];
int cmp(const void *a,const void *b)
{
return (*(struct s *)a).w-(*(struct s *)b).w;
}
int n,m;
int pre[1010],f[1010],vis[1010];
int G[1010][1010],C[1010][1010];
int find(int x,int *pre)
{
if(pre[x]==x)
return x;
return pre[x]=find(pre[x],pre);
}
vector<int>vt[1010];
void init()
{
int i;
for(i=0;i<=n;i++)
{
f[i]=i;
vis[i]=0;
vt[i].clear();
}
}
int det(int a[][1010],int n)//<span class="comment" style="font-family: arial, verdana, helvetica, sans-serif;">生成树计数:Matrix-Tree定理 </span><span style="font-family: arial, verdana, helvetica, sans-serif;"> </span>
{
int i,j,k;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
a[i][j]%=mod;
}
}
int ret=1;
for(i=1;i<n;i++)
{
for(j=i+1;j<n;j++)
{
while(a[j][i])
{
int t=a[i][i]/a[j][i];
for(k=i;k<n;k++)
{
a[i][k]=(a[i][k]-a[j][k]*t)%mod;
}
for(k=i;k<n;k++)
{
swap(a[i][k],a[j][k]);
}
ret=-ret;
}
}
if(a[i][i]==0)
{
return 0;
}
ret=ret*a[i][i]%mod;
}
if(ret<0)
ret=-ret;
return (ret+mod)%mod;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int i,j,k;
memset(G,0,sizeof(G));
for(i=0;i<m;i++)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
if(m==0)
{
printf("0\n");
continue;
}
qsort(edge,m,sizeof(edge[0]),cmp);
init();
int w=-1,a,b;
long long ans=1;
for(k=0;k<=m;k++)
{
if(edge[k].w!=w||k==m)
{
for(i=1;i<=n;i++)
{
if(vis[i])
{
int u=find(i,pre);
vt[u].push_back(i);
vis[i]=0;
}
}
for(i=1;i<=n;i++)
{
if(vt[i].size()>1)
{
int len=vt[i].size();
//  memset(C,0,sizeof(C));
for(a=1;a<=n;a++)
for(b=1;b<=n;b++)
C[a][b]=0;
for(a=0;a<len;a++)
{
for(b=a+1;b<len;b++)
{
int a1=vt[i][a];
int b1=vt[i][b];
C[b][a]-=G[a1][b1];
C[a][b]=C[b][a];
C[a][a]+=G[a1][b1];
C[b][b]+=G[a1][b1];
}
}
int ret=det(C,len);
//      printf("+++++%d\n",ret);
ans=(ans*ret)%mod;
for(a=0;a<len;a++)
{
f[vt[i][a]]=i;
}
}
}
for(i=1;i<=n;i++)
{
pre[i]=f[i]=find(i,f);
vt[i].clear();
}
if(k==m)
break;
w=edge[k].w;
}
int a=edge[k].u;
int b=edge[k].v;
int fa=find(a,f);
int fb=find(b,f);

if(fa!=fb)
{
int fx=find(fa,pre),fy=find(fb,pre);
vis[fa]=vis[fb]=1;
pre[fx]=fy;
G[fa][fb]++;
G[fb][fa]++;
}
}
//  printf("%d\n",ans);
int flag=0;
for(i=2;i<=n;i++)
{
if(flag)
break;
if(pre[i]!=pre[i-1])
flag=1;
}
if(!flag)
printf("%lld\n",ans);
else
printf("0\n");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: