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
Solution
这题目,鬼畜至极。。。看了题解,又发现是矩阵树。。然后经过非常合理的判断,这个题目有一个非常友好的性质——具有相同权值的边不会超过10条。这样就使暴力搜索这种做法成为了可能的做法。
YY一下, 我们可以知道对于我们已经求出的一棵最小生成树,其中每种权值的边的数量就已经是确定的了。那么我们枚举每一种权值的边,判断它有几种方案可行即可。又由于刚才那个美妙的性质,我们每一种边权的最大枚举次数最多是1024。
Code
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#define re register
#define mo 31011
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(arr) memset(arr, 0, sizeof(arr))
const int inf = 0x3f3f3f3f;
struct po
{
int x,y,l;
};
po a[1010];
struct tt
{
int l,r,v;
} p[1010];
int n,m,t,cnt,num,f[1001],sum,tot;
inline int read()
{
int x=0,c=1;
char ch=' ';
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
while(ch=='-') c*=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
return x*c;
}
inline bool cmp(po a,po b)
{
return a.l<b.l;
}
inline int find(int x)
{
return x==f[x]?x:find(f[x]);
}
void dfs(int x,int now,int k)
{
if(now==p[x].r+1){
if(k==p[x].v) sum++;
return;
}
int r1=find(a[now].x),r2=find(a[now].y);
if(r1!=r2){
f[r1]=r2;
dfs(x,now+1,k+1);
f[r1]=r1;f[r2]=r2;
}
dfs(x,now+1,k);
}
int main()
{
n=read();m=read();
for(re int i=1;i<=m;i++)
a[i].x=read(),a[i].y=read(),a[i].l=read();
for(re int i=1;i<=n;i++) f[i]=i;
sort(a+1,a+m+1,cmp);
for(re int i=1;i<=m;i++){
if(a[i].l!=a[i-1].l) cnt++,p[cnt].l=i,p[cnt-1].r=i-1;
int r1=find(a[i].x),r2=find(a[i].y);
if(r1!=r2) f[r1]=r2,p[cnt].v++,tot++;
}
if(tot!=n-1) {
cout<<0;
return 0;
}
p[cnt].r=m;
int ans=1;
for(re int i=1;i<=n;i++) f[i]=i;
for(re int i=1;i<=cnt;i++){
sum=0;
dfs(i,p[i].l,0);
ans=(ans*sum)%mo;
for(re int j=p[i].l;j<=p[i].r;j++){
int r1=find(a[j].x),r2=find(a[j].y);
if(r1!=r2) f[r1]=r2;
}
}
cout<<ans;
return 0;
}