1016: [JSOI2008]最小生成树计数
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 3569 Solved: 1425
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
感觉这个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"); }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-12-17 16:01:50