BZOJ1016 JSOI2008最小生成树计数
定理,在所有最小生成树中,相同边权的边出现的次数相同。
由于重复边权小于10条,可以跑2^10暴力
#include<bits/stdc++.h> using namespace std; const int N=1e3+10,mod=31011; struct node{ int x,y,w; bool operator <(const node &b)const{ return w<b.w; } }e[N]; struct poin{ int l,r,v; }a[N]; int n,m,sum,ans=1,f[N],cnt; inline int get(int x){return x==f[x]?x:get(f[x]);} void dfs(int x,int now,int num) { if(num==a[x].v){ sum++;return; } if(now>a[x].r)return; int fx=get(e[now].x),fy=get(e[now].y); if(fx!=fy){ f[fx]=fy;dfs(x,now+1,num+1); f[fx]=fx;f[fy]=fy; } dfs(x,now+1,num); } inline int read() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9'){ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } int main() { n=read();m=read(); for(int i=1;i<=m;++i) { e[i].x=read();e[i].y=read();e[i].w=read(); } sort(e+1,e+1+m); for(int i=1;i<=n;++i)f[i]=i;int num=0; for(int i=1;i<=m;++i) { if(e[i].w!=e[i-1].w)a[++cnt].l=i,a[cnt-1].r=i-1; int fx=get(e[i].x),fy=get(e[i].y); if(fx!=fy) { f[fx]=fy;a[cnt].v++;num++; } } if(num!=n-1){puts("0");return 0;} a[cnt].r=m;for(int i=1;i<=n;++i)f[i]=i; for(int i=1;i<=cnt;++i) { sum=0; dfs(i,a[i].l,0); ans=1ll*ans*sum%mod; for(int j=a[i].l;j<=a[i].r;++j) { int fx=get(e[j].x),fy=get(e[j].y); if(fx!=fy)f[fx]=fy; } } printf("%d",ans); return 0; }
生命中真正重要的不是你遭遇了什么,而是你记住了哪些事,又是如何铭记的。