P4208 [JSOI2008]最小生成树计数

Captain_Paul

2018-09-26 14:47:03

Personal

题意:求无向图的最小生成树个数 ------------ 不同的最小生成树方案,每一种权值的边数量和作用是一定的 先做一遍最小生成树,得出每一种权值的边的使用情况 对于每一种权值的边搜索,得到ta的选择情况 乘法原理统计答案 ``` #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define reg register using namespace std; const int N=1e5+5,mod=31011; struct E { int from,to,dis; inline friend bool operator < (E a,E b) {return a.dis<b.dis;} }e[N<<1]; struct Data { int l,r,dis; }a[N<<1]; int n,m,cnt,sum,ans=1,tot,f[N]; inline int read() { int x=0,w=1; char c=getchar(); while (!isdigit(c)&&c!='-') c=getchar(); if (c=='-') c=getchar(),w=-1; while (isdigit(c)) { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x*w; } int find(int x){return f[x]==x?x:find(f[x]);} void dfs(int k,int now,int x) { if (now==a[k].r+1) { if (a[k].dis==x) ++sum; return; } int u=find(e[now].from); int v=find(e[now].to); if (u!=v) { f[u]=v; dfs(k,now+1,x+1); f[u]=u; f[v]=v; } dfs(k,now+1,x); } int main() { n=read(),m=read(); for (reg int i=1;i<=m;i++) { int x=read(),y=read(),z=read(); e[i]=(E){x,y,z}; } sort(e+1,e+m+1); for (reg int i=1;i<=n;i++) f[i]=i; for (reg int i=1;i<=m;i++) { int u=find(e[i].from); int v=find(e[i].to); if (e[i].dis!=e[i-1].dis) a[cnt].r=i-1,a[++cnt].l=i; if (u!=v) f[u]=v,++tot,++a[cnt].dis; } a[cnt].r=m; if (tot!=n-1) {puts("0"); return 0;} for (reg int i=1;i<=n;i++) f[i]=i; for (reg int i=1;i<=cnt;i++) { sum=0; dfs(i,a[i].l,0); ans=(ans*sum)%mod; for (reg int j=a[i].l;j<=a[i].r;j++) { int u=find(e[j].from); int v=find(e[j].to); if (u!=v) f[u]=v; } } printf("%d\n",ans); return 0; } ```