BZOJ 1016: [JSOI2008]最小生成树计数
2017-08-12 08:40
267 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=1016
题意:
![](https://images2017.cnblogs.com/blog/1047463/201708/1047463-20170812083636773-1690188514.jpg)
思路:
一个无向图所有的最小生成树中某种权值的边的数目均相同。
引用一篇大牛的证明:
我们证明以下定理:一个无向图所有的最小生成树中某种权值的边的数目均相同。
开始时,每个点单独构成一个集合。
首先只考虑权值最小的边,将它们全部添加进图中,并去掉环,由于是全部尝试添加,那么只要是用这种权值的边能够连通的点,最终就一定能在一个集合中。
那么不管添加的是哪些边,最终形成的集合数都是一定的,且集合的划分情况一定相同。那么真正添加的边数也是相同的。因为每添加一条边集合的数目便减少1.
那么权值第二小的边呢?我们将之间得到的集合每个集合都缩为一个点,那么权值第二小的边就变成了当前权值最小的边,也有上述的结论。
因此每个阶段,添加的边数都是相同的。我们以权值划分阶段,那么也就意味着某种权值的边的数目是完全相同的。
所以先用克鲁斯卡尔算法计算一遍最小生成树,统计每一权值的边组需要加几条边,最后暴搜,乘法原理相乘即可。注意,要判断无法连通的情况。
题意:
![](https://images2017.cnblogs.com/blog/1047463/201708/1047463-20170812083636773-1690188514.jpg)
思路:
一个无向图所有的最小生成树中某种权值的边的数目均相同。
引用一篇大牛的证明:
我们证明以下定理:一个无向图所有的最小生成树中某种权值的边的数目均相同。
开始时,每个点单独构成一个集合。
首先只考虑权值最小的边,将它们全部添加进图中,并去掉环,由于是全部尝试添加,那么只要是用这种权值的边能够连通的点,最终就一定能在一个集合中。
那么不管添加的是哪些边,最终形成的集合数都是一定的,且集合的划分情况一定相同。那么真正添加的边数也是相同的。因为每添加一条边集合的数目便减少1.
那么权值第二小的边呢?我们将之间得到的集合每个集合都缩为一个点,那么权值第二小的边就变成了当前权值最小的边,也有上述的结论。
因此每个阶段,添加的边数都是相同的。我们以权值划分阶段,那么也就意味着某种权值的边的数目是完全相同的。
所以先用克鲁斯卡尔算法计算一遍最小生成树,统计每一权值的边组需要加几条边,最后暴搜,乘法原理相乘即可。注意,要判断无法连通的情况。
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<sstream> #include<vector> #include<stack> #include<queue> #include<cmath> #include<map> #include<set> using namespace std; typedef long long ll; typedef pair<int,ll> pll; const int INF = 0x3f3f3f3f; const int maxn=10000+5; const int mod=31011; struct node { int u,v,w; }e[10*maxn]; struct node2 { int l,r; int c; }a[maxn]; int n, m; int sum; int cnt,tot; int p[maxn]; bool cmp(node a, node b) { return a.w<b.w; } int find(int x) { return x==p[x]?x:find(p[x]); } void dfs(int cur, int num ,int pos) { if(pos>a[cur].r) { if(num==a[cur].c) sum++; return; } int x=find(e[pos].u); int y=find(e[pos].v); if(x!=y) { p[x]=y; dfs(cur,num+1,pos+1); p[x]=x; } dfs(cur,num,pos+1); } int main() { //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { for(int i=1;i<=n;i++) p[i]=i; for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); sort(e+1,e+m+1,cmp); cnt=0; tot=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; a[cnt].c=0; } int x=find(e[i].u); int y=find(e[i].v); if(x!=y) { p[x]=y; a[cnt].c++; tot++; } } a[cnt].r=m; if(tot!=n-1) //连不起来的情况 { printf("0\n"); continue; } for(int i=1;i<=n;i++) p[i]=i; int ans=1; for(int i=1;i<=cnt;i++) { sum=0; dfs(i,0,a[i].l); ans=(ans*sum)%mod; for(int j=a[i].l;j<=a[i].r;j++) { int x=find(e[j].u); int y=find(e[j].v); if(x!=y) p[x]=y; } } printf("%d\n",ans); } return 0; }
相关文章推荐
- 【bzoj1016】【JSOI2008】【最小生成树计数】【dfs+最小生成树】
- 【JSOI2008】【BZOJ1016】最小生成树计数
- bzoj1016 [JSOI2008]最小生成树计数
- bzoj1016 [JSOI2008]最小生成树计数
- BZOJ1016 [JSOI2008]最小生成树计数
- BZOJ 1016 [JSOI2008]最小生成树计数
- [BZOJ]1016 JSOI2008 最小生成树计数
- Bzoj1016: [JSOI2008]最小生成树计数
- 【bzoj1016】 JSOI2008—最小生成树计数
- bzoj1016: [JSOI2008]最小生成树计数
- bzoj1016 [JSOI2008]最小生成树计数
- 【BZOJ】1016: [JSOI2008]最小生成树计数
- bzoj1016: [JSOI2008]最小生成树计数(最小生成树+搜索)
- [BZOJ1016][JSOI2008]最小生成树计数(Kruskal+计数)
- 【BZOJ1016】【JSOI2008】最小生成树计数
- 【bzoj1016】[JSOI2008]最小生成树计数
- bzoj1016:[JSOI2008]最小生成树计数
- bzoj 1016: [JSOI2008]最小生成树计数
- 【Kruskal+dfs】BZOJ1016- [JSOI2008]最小生成树计数
- 【JSOI 2008】【BZOJ 1016】最小生成数计数