题意:你认为我会告诉你题意么?!!!
题解:
首先我们把边长从小到大排个序,这是显然的!
然后我们把边长相同的分个组,难道你要问我为什么?
然后我们在处理每个边组之前先存一下当前并查集状态,这是显然的!
然后我们状态压缩枚举每种选边方案,看是否正确,难道你要问我为什么?
只要边的两个节点所处集不同,然后加的边不会少个几条就是一种正确方案,这是显然的!
这里就涉及了一个很好推的小性质:每个边组处理完了以后,无论是哪种方案,最后达成的并查集状态都是一定的,而且用的边数也都是一定的,啊?难道你要问我为什么?
说完了,另外,要注意可能不存在最小生成树,我为了这个调了一下午,这是不科学的!
好了,贴写得还可以的代码,另外,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; }