http://acm.hdu.edu.cn/showproblem.php?pid=4408

题意:求最小生成树个数

题解:对于Kruskal算法,我们发现,最小生成树要想用多种方法就要有长度相同的边。而且,我们发现,kruskal处理完长度所有为c1的边之后,他的结果就是用长度为c1的边生成了一棵树,而且这棵树对于下面的影响都是一样的,因为只有效果重复的边才不会被加入集合,所以我们只需要记录每一个阶段的生成树个数然后相乘就可以了。

实现起来,在一个阶段内,要想有多种方法,必定是有的边成环了,也就是形成了联通块,所以我们只需要找到联通块,然后在这些联通块内生成树就可以了。我们用并查集维护缩点。具体细节看注释。

代码:

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn =105;
const int maxm =1005;
//生成树计数模板
ll mode;
ll a[maxn][maxn];//生成树计数模板
ll det(int n){int i,j,k;ll ans=1;for(i=0;i<n;i++)for(j=0;j<n;j++)a[i][j]%=mode;for(i=0;i<n;i++){for(j=i+1;j<n;j++){while(a[j][i]){int tmp=a[i][i]/a[j][i];for(k=i;k<n;k++){a[i][k]=((a[i][k]-tmp*a[j][k])%mode+mode)%mode;swap(a[i][k],a[j][k]);}ans=-ans;}}if(a[i][i]==0)return 0;ans=ans*a[i][i]%mode;}return (ans%mode+mode)%mode;
}
///并查集部分
//over_p记录之前已经更新过的所有的关系,now_p记录当前这一层的关系
int now_p[maxn],over_p[maxn];
int finde(int x,int p[]){return p[x]==x?x:p[x]=finde(p[x],p);
}
void join(int x,int y,int p[]){x=finde(x,p);y=finde(y,p);if(x==y)return ;p[x]=y;return ;
}
//slove
struct node{int u,v,w;
}e[maxm];
bool cmp(node a,node b){return a.w<b.w;
}
int n,m;
ll ans;
int vis[maxn];
vector<int> g[maxn];
void init(){int i;for(i=0;i<n;i++){now_p[i]=i;over_p[i]=i;g[i].clear();}memset(vis,0,sizeof(vis));sort(e,e+m,cmp);
}
int mp[maxn][maxn];
ll max_mst_num(){if(m==0)return 0;ans=1;int i,j;int x,y;init();int now=e[0].w;for(i=0;i<=m;i++){if(e[i].w==now&&i!=m){//查找被缩成的点x=finde(e[i].u,over_p);y=finde(e[i].v,over_p);if(x==y)continue;//之前被缩为一点join(x,y,now_p);//在一个集合内等待缩点vis[x]=1;vis[y]=1;mp[x][y]++;//邻接矩阵不再是0,1矩阵,因为这里进行了缩点,要保存这一点所有的关系mp[y][x]++;}else {for(j=0;j<n;j++){if(vis[j]){vis[j]=0;g[finde(j,now_p)].push_back(j);//将一个联通块加入一个vector}}for(j=0;j<n;j++){if(g[j].size()>1){int len=g[j].size();memset(a,0,sizeof(a));for(x=0;x<len;x++){for(y=x+1;y<len;y++){int tmp1,tmp2;tmp1=g[j][x];tmp2=g[j][y];a[x][y]=a[y][x]=-mp[tmp1][tmp2];a[x][x]+=mp[tmp1][tmp2];a[y][y]+=mp[tmp1][tmp2];//x,y为点在这一联通块内的编号,计算时用这个编号形成的矩阵}}ans=(ans*det(len-1)%mode+mode)%mode;//对这一联通块生成树计数for(x=0;x<len;x++)over_p[g[j][x]]=j;//将这一层的关系记录到全局关系中}}memset(mp,0,sizeof(mp));//初始化当前关系为下一轮准备for(j=0;j<n;j++){now_p[j]=finde(j,over_p);g[j].clear();}now=e[i].w;if(i>=m)break;i--;}}now=finde(0,over_p);for(i=0;i<n;i++)if(finde(i,over_p)!=now)return 0;return ans;
}
int main()
{int i;//freopen("1.txt","r",stdin);while(cin>>n>>m>>mode){if(n==0&&m==0&&mode==0)break;for(i=0;i<m;i++){scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);e[i].v--;e[i].u--;//别忘了}ll ans=max_mst_num();ans=(ans%mode+mode)%mode;printf("%lld\n",ans);}// cout << "Hello world!" << endl;return 0;
}

HDU 4408 Minimum Spanning Tree 最小生成树计数相关推荐

  1. HDU 4408 - Minimum Spanning Tree(最小生成树计数)

    有边权的最小生成树计数 模板 #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostre ...

  2. hdu 4408 Minimum Spanning Tree

    题目连接:点击打开链接 解法:利用kruskal算法 把图划分成森林, 同一点有相同最小的权值到别的点, 通过determinant计算树的课数. 总结:模板 + 自己不太懂 = 记录 + 重新学 代 ...

  3. 第十三章 ALDS1_12_A:Minimum Spanning Tree 最小生成树

    知识点 树是没有环的图 在树中,任意顶点r和顶点v之间必然存在着1条路径 生成树:拥有图G的所有顶点,并且在保证自身是树的前提下拥有尽量多的边. 最小生成树(MST):个边权值总和最小的生成树 普里姆 ...

  4. Minimum spanning tree HDU - 6954

    Minimum spanning tree HDU - 6954 题意: 给定n-1个点,编号从2到n,两点a和b之间的边权重为lcm(a,b).请找出它们形成的最小生成树. 2<=n<= ...

  5. Directed Minimum Spanning Tree: Chu-Liu/Edmonds Algorithm

    我们的现代数据库大作业要求实现一个图查询系统,包括基于属性的子图查询.可达性查询(可选).最短路径查询(可选).TopK最短路径查询(可选).图形化展示(可选)等功能.分成子图同构查询小组以及可达性及 ...

  6. 《Boost》Part1 Minimum Spanning Tree

    <Boost>Part1 Minimum Spanning Tree 1.Boost中的最小生成树介绍 MST最小生成树,是图论中的基本算法,还有一种是最大生成树,此处暂不介绍. 最小生成 ...

  7. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  8. 最小生成树(MST,minimum spanning tree)

    生成树:由图生成的树,由图转化为树,进一步可用对树的相关操作来对图进行操作.最小指的是权值最小: 生成树是边的集合,如下图所示的最小生成树:MST={{a,b},{a,f},{f,c}}\text{M ...

  9. 最小生成树(Minimum Spanning Tree)与最小树形图(Minimum Arborescence)问题

    没整理完 生成树:给图中指定一个特殊的点root,选择图中部分已有边生成一棵以root为根的生成树T. 最小生成树:在无向图中生成一棵树,含有的边的总权值要求是所有可能生成树中最小的,该树不唯一. 最 ...

最新文章

  1. android media sessiom,如何使用新的MediaSession类在Android 5.x上接收...
  2. python无法处理特别大的数据文件_Python实现快速大文件比较代码解析
  3. 使用antd UI组件有感
  4. Android ANR 分析
  5. 2019CCF自主可控计算机大会召开 中科院院士吁自力更生
  6. 0913作业(冒泡排序、二分查找法、模拟摇乐游戏)
  7. 多维数组的索引与切片_Numpy库使用入门(二)数据的索引和切片
  8. Linux并发服务器编程之多线程并发服务器
  9. Nexus 3.31.1 maven 私服 仓库和IntelliJ IDEA 2021.2 实战篇 linux
  10. 零火线都带电该怎么处理?
  11. [Python + PyQt5] 均匀平面波的入射、反射及透射的仿真实验
  12. java web程序设计任务驱动教程答案,Java Web应用程序开发任务驱动式教程
  13. linux freemind字体,解决 ubuntu 18.04 lts freemind 或freeplane 乱码口口的问题
  14. 医院信息系统(HIS系统)如何接入短信/语音功能
  15. 记:判断三个点是否在一条直线上
  16. PIL imagefont 添加下划线
  17. DP\记忆化搜索-牛客寒假集训营3-牛牛的DRB迷宫I
  18. 【NIPS 2017】PointNet++:度量空间中点集的深层次特征学习
  19. java:程序包XXX不存在
  20. 2022.12.9 英语背诵

热门文章

  1. Qt (高仿Visio)流程图组件开发(三) 图元基类如何定义,流程图多种图元类型实现
  2. 辅助系统(Flume,azkaban,sqoop)
  3. 给服务器写一个简单的断网重连shell脚本
  4. 《牛客刷verilog》Part III Verilog企业真题
  5. 安全加密 - 秘钥和算法关系
  6. 弘辽科技:想做好标题优化,这些错误不能犯。
  7. 小朋友排队(树状数组)
  8. Adlik在深度学习异构计算上的实践
  9. 不会被和谐的良心云端储存网盘? 试试MEGA吧!
  10. vscode 新建cpp文件_vscode怎样新建项目和文件 值得收藏