Bzoj1016 最小生成树计数
Time Limit: 1000MS | Memory Limit: 165888KB | 64bit IO Format: %lld & %llu |
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
Sample Output
8
Hint
Source
JSOI2008
kruskal算法的改版。
首先按照kruskal的思想做最小生成树,但是处理的时候,把所有边权相同的边记录下来,分进一组。
之后试着从每组里dfs选边,使整张图连通,在这个过程中就可以统计出方案数
读入的边出入点要离散化。注意数组范围。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 const int mxn=10000; 8 int n,m; 9 int sum; 10 int ans=1; 11 // 12 struct edge{//边 13 int x,y; 14 int v; 15 }e[mxn]; 16 struct segment{ 17 int st,ed;//区块起止点 18 int v; 19 }se[mxn]; 20 int cnt; 21 int cmp(const edge a,const edge b){ 22 return a.v<b.v; 23 } 24 // 25 int fa[mxn]; 26 int find(int x){ 27 if(fa[x]==x)return x; 28 return find(fa[x]);//不可压缩 29 } 30 // 31 void dfs(int x,int now,int t){//x 组编号 now现在处理的边编号 t使用的边编号 32 if(now==se[x].ed+1){ 33 if(t==se[x].v)sum++; 34 return; 35 } 36 int u=find(e[now].x),v=find(e[now].y); 37 if(u!=v){ 38 fa[u]=v; 39 dfs(x,now+1,t+1);//选用这条边 40 fa[u]=u;fa[v]=v;//还原状态 41 } 42 dfs(x,now+1,t);//不选这条边 43 return; 44 } 45 46 int main(){ 47 scanf("%d%d",&n,&m); 48 int i,j; 49 for(i=1;i<=n;i++)fa[i]=i;//初始化并查集,处理边的连通 50 for(i=1;i<=m;i++) 51 scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v); 52 sort(e+1,e+m+1,cmp); 53 int tot=0;//联通边数 54 for(i=1;i<=m;i++){ 55 if(e[i].v!=e[i-1].v){//如果权值与之前不同 56 se[cnt].ed=i-1;se[++cnt].st=i;//分到新的一组 57 } 58 int u=find(e[i].x); 59 int v=find(e[i].y); 60 if(u!=v){fa[u]=v;se[cnt].v++;tot++;} 61 } 62 se[cnt].ed=m; 63 if(tot!=n-1){printf("0");return 0;}//未联通 64 for(i=1;i<=n;i++)fa[i]=i;//初始化并查集,处理边组的连通 65 for(i=1;i<=cnt;i++){ 66 sum=0; 67 dfs(i,se[i].st,0); 68 ans=(ans*sum)%31011; 69 for(j=se[i].st;j<=se[i].ed;j++){ 70 int u=find(e[j].x),v=find(e[j].y); 71 if(u!=v)fa[u]=v; 72 } 73 } 74 printf("%d",ans%31011); 75 return 0; 76 }
本文为博主原创文章,转载请注明出处。