HDU 4408 Minimum Spanning Tree 最小生成树计数
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 最小生成树计数相关推荐
- HDU 4408 - Minimum Spanning Tree(最小生成树计数)
有边权的最小生成树计数 模板 #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostre ...
- hdu 4408 Minimum Spanning Tree
题目连接:点击打开链接 解法:利用kruskal算法 把图划分成森林, 同一点有相同最小的权值到别的点, 通过determinant计算树的课数. 总结:模板 + 自己不太懂 = 记录 + 重新学 代 ...
- 第十三章 ALDS1_12_A:Minimum Spanning Tree 最小生成树
知识点 树是没有环的图 在树中,任意顶点r和顶点v之间必然存在着1条路径 生成树:拥有图G的所有顶点,并且在保证自身是树的前提下拥有尽量多的边. 最小生成树(MST):个边权值总和最小的生成树 普里姆 ...
- Minimum spanning tree HDU - 6954
Minimum spanning tree HDU - 6954 题意: 给定n-1个点,编号从2到n,两点a和b之间的边权重为lcm(a,b).请找出它们形成的最小生成树. 2<=n<= ...
- Directed Minimum Spanning Tree: Chu-Liu/Edmonds Algorithm
我们的现代数据库大作业要求实现一个图查询系统,包括基于属性的子图查询.可达性查询(可选).最短路径查询(可选).TopK最短路径查询(可选).图形化展示(可选)等功能.分成子图同构查询小组以及可达性及 ...
- 《Boost》Part1 Minimum Spanning Tree
<Boost>Part1 Minimum Spanning Tree 1.Boost中的最小生成树介绍 MST最小生成树,是图论中的基本算法,还有一种是最大生成树,此处暂不介绍. 最小生成 ...
- CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)
题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...
- 最小生成树(MST,minimum spanning tree)
生成树:由图生成的树,由图转化为树,进一步可用对树的相关操作来对图进行操作.最小指的是权值最小: 生成树是边的集合,如下图所示的最小生成树:MST={{a,b},{a,f},{f,c}}\text{M ...
- 最小生成树(Minimum Spanning Tree)与最小树形图(Minimum Arborescence)问题
没整理完 生成树:给图中指定一个特殊的点root,选择图中部分已有边生成一棵以root为根的生成树T. 最小生成树:在无向图中生成一棵树,含有的边的总权值要求是所有可能生成树中最小的,该树不唯一. 最 ...
最新文章
- android media sessiom,如何使用新的MediaSession类在Android 5.x上接收...
- python无法处理特别大的数据文件_Python实现快速大文件比较代码解析
- 使用antd UI组件有感
- Android ANR 分析
- 2019CCF自主可控计算机大会召开 中科院院士吁自力更生
- 0913作业(冒泡排序、二分查找法、模拟摇乐游戏)
- 多维数组的索引与切片_Numpy库使用入门(二)数据的索引和切片
- Linux并发服务器编程之多线程并发服务器
- Nexus 3.31.1 maven 私服 仓库和IntelliJ IDEA 2021.2 实战篇 linux
- 零火线都带电该怎么处理?
- [Python + PyQt5] 均匀平面波的入射、反射及透射的仿真实验
- java web程序设计任务驱动教程答案,Java Web应用程序开发任务驱动式教程
- linux freemind字体,解决 ubuntu 18.04 lts freemind 或freeplane 乱码口口的问题
- 医院信息系统(HIS系统)如何接入短信/语音功能
- 记:判断三个点是否在一条直线上
- PIL imagefont 添加下划线
- DP\记忆化搜索-牛客寒假集训营3-牛牛的DRB迷宫I
- 【NIPS 2017】PointNet++:度量空间中点集的深层次特征学习
- java:程序包XXX不存在
- 2022.12.9 英语背诵