描述
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的 最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生 成树可能很多,所以你只需要输出方案数对31011的模就可以了。
输入
第一行包含两个数,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条。
输出
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
样例输入 [复制]
4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
样例输出 [复制]
8
//
用样例来理解最小生成树计数,发现限制很多
1.对于不同的最小生成树,边权总和是相等的,所以每一种边权的边的数量必须是不变的
2.既然有上述条件,可以对相同边权的边枚举看是否满足要求(相同权值的边的数目不超过10,赤裸裸的状压啊),(枚举的过程,相当于把不同的几个点连接到已经产生的最小的集合中,成为新的集合)
2.1 如果顺着推下去,那么不同的连接情况是否会对后面的边的连接情况产生影响?
是不会的。 如果会有影响,说明有部分点没有连接到当前最小的集合,但当前是最优解,必须连接完所有可能连接的点。所以边虽然不一样,但最后加入最优解集合的点一定是完全相同的
2.2 枚举情况要确定总数。任一权值的边的数量在最小生成树中都是不变的,所以先做一遍最小生成树,维护当前权值边的数量来作为约束条件即可(从另一个的角度,相当于框定一个大的范围来优化时间)
2.3 注意当前边不能成环
(代码学习了某不知姓名的大佬的写法https://blog.csdn.net/wyfcyx_forever/article/details/40182739)
(这个代码最坏情况 1e7)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+10,mod=31011;
struct edge{
int u,v,s;
inline void read(){
scanf("%d%d%d",&u,&v,&s);
}
bool operator <(const edge &t) const{
return s<t.s;
}
}e[1005];
map<int,int> M;
int n,m;
int fa[maxn],bet[maxn];
inline int find(int u){
int again