bzo1016: [JSOI2008]最小生成树计数
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。
跑一遍克鲁斯卡尔,记录每种权值的边有多少条,然后状压枚举满足条件的所有边乘到答案中即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/************************************************************** Problem: 1016 User: walfy Language: C++ Result: Accepted Time:68 ms Memory:1452 kb ****************************************************************/ //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,no-stack-protector") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") //#pragma GCC optimize("unroll-loops") #include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define vi vector<int> #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pli pair<ll,int> #define pii pair<int,int> #define cd complex<double> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=1000+10,maxn=200000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f; struct edge{ int u,v,c; bool operator<(const edge &rhs)const{ return c<rhs.c; } }e[N]; map<int,int>ans,id; vector<pii>v[N]; int fa[N],prefa[N]; int Find(int x) { return fa[x]==x?x:fa[x]=Find(fa[x]); } int main() { fio; int n,m; cin>>n>>m; for(int i=1;i<=n;i++)fa[i]=i; int cnt=0; for(int i=0;i<m;i++) { int a,b,c; cin>>a>>b>>c; e[i]={a,b,c}; } sort(e,e+m); for(int i=0;i<m;i++) { if(!id[e[i].c])id[e[i].c]=++cnt; v[id[e[i].c]].pb(mp(e[i].u,e[i].v)); int x=e[i].u,y=e[i].v; int fx=Find(x),fy=Find(y); if(fx!=fy)fa[fx]=fy,ans[e[i].c]++; } for(int i=2;i<=n;i++) if(Find(i)!=Find(i-1)) { cout<<0<<"\n"; return 0; } for(int i=1;i<=n;i++)fa[i]=i; map<int,int>::iterator it=id.begin(); ll res=1; for(;it!=id.end();it++) { for(int i=1;i<=n;i++)prefa[i]=fa[i]; // for(int i=0;i<v[it->se].size();i++)printf("%d %d %d\n",i,v[it->se][i].fi,v[it->se][i].se); // puts(""); ll len=v[it->se].size(),go=-1,pp=0; for(int i=0;i<(1<<len);i++) { int num=0; for(int j=0;j<len;j++) if((i>>j)&1) num++; if(num!=ans[it->fi])continue; else { bool ok=1; for(int j=0;j<len;j++) { if((i>>j)&1) { int x=v[it->se][j].fi,y=v[it->se][j].se; int fx=Find(x),fy=Find(y); if(fx!=fy)fa[fx]=fy; else ok=0; } } if(ok)pp++,go=i;//,printf("%d\n",i); } for(int j=1;j<=n;j++)fa[j]=prefa[j]; } // printf("%d\n",pp); res=(res*pp)%31011; if(go==-1)continue; for(int j=0;j<len;j++) { if((go>>j)&1) { int x=v[it->se][j].fi,y=v[it->se][j].se; int fx=Find(x),fy=Find(y); if(x!=y)fa[fx]=fy; } } } cout<<res<<"\n"; return 0; } /*********************** 4 6 1 2 1 1 3 1 1 4 1 2 3 2 2 4 1 3 4 3 ***********************/