题意:你认为我会告诉你题意么?!!!
题解:
首先我们把边长从小到大排个序,这是显然的!
然后我们把边长相同的分个组,难道你要问我为什么?
然后我们在处理每个边组之前先存一下当前并查集状态,这是显然的!
然后我们状态压缩枚举每种选边方案,看是否正确,难道你要问我为什么?
只要边的两个节点所处集不同,然后加的边不会少个几条就是一种正确方案,这是显然的!
这里就涉及了一个很好推的小性质:每个边组处理完了以后,无论是哪种方案,最后达成的并查集状态都是一定的,而且用的边数也都是一定的,啊?难道你要问我为什么?
说完了,另外,要注意可能不存在最小生成树,我为了这个调了一下午,这是不科学的!
好了,贴写得还可以的代码,另外,dfs处可以用状态压缩式写法,可能代码复杂度还会低点,而时间是一定小的。。。额,虽然题目中每个边组元素个数<=10的意思就是让你写暴力验证,但是还有一种Matrix Tree定理的高速做法!强烈点赞!快去看吧!
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 105
#define M 1005
#define K 11
#define mod 31011
#define inf 0x3f3f3f3f
using namespace std;
struct KSD
{
int u,v,len;
bool operator < (const KSD &a)const
{return len<a.len;}
}road[M];
int f[3][N],n,m;
int find(int p,int x)
{
if(f[p][x]==x)return x;
return f[p][x]=find(p,f[p][x]);
}
int ans=1,ret,head,tail,edge;
bool visit[M];
void dfs(int dep)
{
if(dep==tail)
{
int i,fa,fb,E=0;
for(i=1;i<=n;i++)f[1][i]=f[0][i];
for(i=head;i<tail;i++)if(visit[i])
{
fa=find(1,road[i].u);
fb=find(1,road[i].v);
if(fa==fb)return ;
f[1][fb]=fa;
E++;
}
if(E==edge)ret++;
return ;
}
visit[dep]=0;dfs(dep+1);
visit[dep]=1;dfs(dep+1);
}
bool Krus()
{
int i,len,zsgg=0;
int fa,fb;
for(i=1;i<=n;i++)f[0][i]=f[2][i]=i;
for(head=1;head<=m;head=tail)
{
len=road[head].len;
tail=head-1;
edge=0;
while(road[++tail].len==len)
{
fa=find(2,road[tail].u);
fb=find(2,road[tail].v);
if(fa!=fb)f[2][fb]=fa,edge++,zsgg++;
}
ret=0;
dfs(head);
ans=ans*ret%mod;
for(i=1;i<=n;i++)f[0][i]=find(2,i);
}
if(zsgg==n-1)return 1;
return 0;
}
int main()
{
// freopen("test.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].len);
sort(road+1,road+m+1);
printf("%d\n",Krus()?ans:0);
return 0;
}