BZOJ 1016 【JSOI2008】 最小生成树计数
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,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过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
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
Sample Output
8
这一次居然自己想出来了一道还算比较难的题,心里好开心O(∩_∩)O~~
这道题用到了最小生成树的几个性质。第一,最小生成树每种边权的边数量一定。第二(由第一点可得),当一个图有多个最小生成树时,只可能由一条边替换掉一条等边权的边来得到一颗新的最小生成树。所以,注意到题目中的一个条件:
具有相同权值的边不会超过10条。
所以我们就非常地开心。因为这样就可以做了。我们把边按权值排序,然后对于每一块权值相同的边搜索哪些边要选,再统计一下方案数就可以AC辣!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 7 #define maxn 5010 8 #define INF (1LL<<50) 9 #define mod 31011 10 11 using namespace std; 12 typedef long long llg; 13 14 struct data{ 15 int u,v,x; 16 bool operator < (const data &h)const{return x<h.x;} 17 }s[maxn]; 18 struct dat1{ 19 int l,r,x; 20 dat1(int a=0,int b=0,int c=0):l(a),r(b),x(c){}; 21 }ss[maxn]; 22 int n,m,fa[maxn],ls,la[maxn],w[maxn]; 23 llg ans=INF,a1,now,aa=1; 24 bool ww[maxn]; 25 26 int getint(){ 27 int w=0,q=0; 28 char c=getchar(); 29 while((c<'0'||c>'9')&&c!='-') c=getchar(); 30 if(c=='-') q=1,c=getchar(); 31 while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); 32 return q?-w:w; 33 } 34 35 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} 36 37 inline void work(){ 38 now=0;int k=0; 39 for(int i=1;i<=n;i++) fa[i]=i; 40 for(int i=1,u,v;i<=m;i++) 41 if(ww[i]){ 42 u=s[i].u;v=s[i].v; 43 if(find(u)!=find(v)){ 44 now+=s[i].x; k++; 45 fa[find(u)]=find(v); 46 } 47 } 48 if(k!=n-1) return; 49 if(now<ans) ans=now,a1=1; 50 else if(now==ans) a1++; 51 } 52 53 void dfs(int res,int now,int dd){ 54 if(now==dd+1){ 55 work();return; 56 } 57 if(res){ 58 ww[now]=1; 59 dfs(res-1,now+1,dd); 60 } 61 if(dd-now+1>res){ 62 ww[now]=0; 63 dfs(res,now+1,dd); 64 } 65 } 66 67 int main(){ 68 n=getint();m=getint(); 69 for(int i=1;i<=m;i++){ 70 s[i].u=getint();s[i].v=getint(); 71 s[i].x=getint(); 72 } 73 sort(s+1,s+m+1); 74 for(int i=1;i<=n;i++) fa[i]=i; 75 for(int i=1,u,v;i<=m;i++){ 76 w[i]=w[i-1]; ww[i]=1; 77 la[i]=i; u=s[i].u;v=s[i].v; 78 if(s[i-1].x==s[i].x) la[i]=la[i-1]; 79 if(find(u)!=find(v)){ 80 now+=s[i].x; w[i]++; 81 fa[find(u)]=find(v); 82 } 83 if(la[i]!=i && s[i+1].x!=s[i].x) 84 ss[++ls]=dat1(la[i],i,w[i]-w[la[i]-1]); 85 } 86 for(int i=1;i<=ls;i++){ 87 ans=INF; 88 dfs(ss[i].x,ss[i].l,ss[i].r); 89 for(int j=ss[i].l;j<=ss[i].r;j++) ww[j]=1; 90 aa*=a1; aa%=mod; 91 } 92 ans%=mod; aa%=mod; 93 printf("%lld",aa); 94 return 0; 95 }