BZOJ 1016: [JSOI2008]最小生成树计数
2015-05-18 10:11
477 查看
最小生成树计数:
最小生成树的两个性质:
1.不同的最小生成树中,每种边出现的个数是确定的
2.不同的生成树中,某一种边连接完成后,形成的联通块状态是一样的
Submit: 3394 Solved: 1341
[Submit][Status][Discuss]
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
[Submit][Status][Discuss]
/* ***********************************************
Author :CKboss
Created Time :2015年05月17日 星期日 09时44分48秒
File Name :BZOJ1016.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long int LL;
const LL maxn=1100;
const LL mod=31011;
LL n,m;
struct Edge
{
LL u,v,len;
}edge[maxn];
bool cmp(Edge a,Edge b) { return a.len<b.len; }
LL q; LL a[maxn]; LL num[maxn];
LL fa[110];
void init()
{
for(LL i=0;i<110;i++) fa[i]=i;
}
LL find(LL u)
{
if(u==fa[u]) return u;
return fa[u]=find(fa[u]);
}
void kruskal()
{
for(LL i=0;i<m;i++)
{
LL u=find(edge[i].u);
LL v=find(edge[i].v);
LL len=edge[i].len;
if(u==v) continue;
else
{
fa[u]=v;
if(a[q]!=len) a[++q]=len;
num[q]++;
}
}
}
LL find2(LL x)
{
if(x==fa[x]) return x;
return find2(fa[x]);
}
LL part[maxn];
void dfs(LL id,LL from,LL to,LL num)
{
if(num==0) { part[id]++; if(part[id]>=mod) part[id]-=mod; return ; }
for(LL i=from;i<=to;i++)
{
LL u=find2(edge[i].u);
LL v=find2(edge[i].v);
if(u==v) continue;
else
{
LL t=fa[u];
fa[u]=v;
dfs(id,i+1,to,num-1);
fa[u]=t;
}
}
}
bool flag;
void Link(LL id,LL from,LL to,LL num)
{
if(flag) return ;
if(num==0) { flag=true; return ; }
for(LL i=from;i<=to&&flag==false;i++)
{
LL u=find2(edge[i].u);
LL v=find2(edge[i].v);
if(u==v) continue;
else
{
LL t=fa[u];
fa[u]=v;
Link(id,i+1,to,num-1);
if(flag) return ;
fa[u]=t;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();
scanf("%lld%lld",&n,&m);
for(LL i=0,u,v,w;i<m;i++)
{
scanf("%lld%lld%lld",&u,&v,&w);
edge[i]=(Edge){u,v,w};
}
sort(edge,edge+m,cmp);
kruskal();
int go=find(1);
for(int i=2;i<=n;i++)
{
if(go==find(i)) continue;
else { go=-1; break; }
}
if(go==-1)
{
puts("0"); return 0;
}
init();
LL from=0,to=0;
for(LL i=1;i<=q;i++)
{
for(LL j=from;j<m;j++)
if(edge[j].len==a[i]) to=j;
dfs(i,from,to,num[i]);
flag=false;
Link(i,from,to,num[i]);
from=to+1;
}
LL ans=part[1]%mod;
for(LL i=2;i<=q;i++)
{
ans*=part[i];
ans%=mod;
}
printf("%lld\n",ans%mod);
return 0;
}
最小生成树的两个性质:
1.不同的最小生成树中,每种边出现的个数是确定的
2.不同的生成树中,某一种边连接完成后,形成的联通块状态是一样的
1016: [JSOI2008]最小生成树计数
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3394 Solved: 1341
[Submit][Status][Discuss]
Description
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。Input
第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。Output
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。Sample Input
4 61 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
Sample Output
8HINT
Source
[Submit][Status][Discuss]
/* ***********************************************
Author :CKboss
Created Time :2015年05月17日 星期日 09时44分48秒
File Name :BZOJ1016.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long int LL;
const LL maxn=1100;
const LL mod=31011;
LL n,m;
struct Edge
{
LL u,v,len;
}edge[maxn];
bool cmp(Edge a,Edge b) { return a.len<b.len; }
LL q; LL a[maxn]; LL num[maxn];
LL fa[110];
void init()
{
for(LL i=0;i<110;i++) fa[i]=i;
}
LL find(LL u)
{
if(u==fa[u]) return u;
return fa[u]=find(fa[u]);
}
void kruskal()
{
for(LL i=0;i<m;i++)
{
LL u=find(edge[i].u);
LL v=find(edge[i].v);
LL len=edge[i].len;
if(u==v) continue;
else
{
fa[u]=v;
if(a[q]!=len) a[++q]=len;
num[q]++;
}
}
}
LL find2(LL x)
{
if(x==fa[x]) return x;
return find2(fa[x]);
}
LL part[maxn];
void dfs(LL id,LL from,LL to,LL num)
{
if(num==0) { part[id]++; if(part[id]>=mod) part[id]-=mod; return ; }
for(LL i=from;i<=to;i++)
{
LL u=find2(edge[i].u);
LL v=find2(edge[i].v);
if(u==v) continue;
else
{
LL t=fa[u];
fa[u]=v;
dfs(id,i+1,to,num-1);
fa[u]=t;
}
}
}
bool flag;
void Link(LL id,LL from,LL to,LL num)
{
if(flag) return ;
if(num==0) { flag=true; return ; }
for(LL i=from;i<=to&&flag==false;i++)
{
LL u=find2(edge[i].u);
LL v=find2(edge[i].v);
if(u==v) continue;
else
{
LL t=fa[u];
fa[u]=v;
Link(id,i+1,to,num-1);
if(flag) return ;
fa[u]=t;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();
scanf("%lld%lld",&n,&m);
for(LL i=0,u,v,w;i<m;i++)
{
scanf("%lld%lld%lld",&u,&v,&w);
edge[i]=(Edge){u,v,w};
}
sort(edge,edge+m,cmp);
kruskal();
int go=find(1);
for(int i=2;i<=n;i++)
{
if(go==find(i)) continue;
else { go=-1; break; }
}
if(go==-1)
{
puts("0"); return 0;
}
init();
LL from=0,to=0;
for(LL i=1;i<=q;i++)
{
for(LL j=from;j<m;j++)
if(edge[j].len==a[i]) to=j;
dfs(i,from,to,num[i]);
flag=false;
Link(i,from,to,num[i]);
from=to+1;
}
LL ans=part[1]%mod;
for(LL i=2;i<=q;i++)
{
ans*=part[i];
ans%=mod;
}
printf("%lld\n",ans%mod);
return 0;
}
相关文章推荐
- BZOJ1016 JSOI2008最小生成树计数
- bzoj1016 [JSOI2008]最小生成树计数
- 【BZOJ 1016】 [JSOI2008]最小生成树计数(matrix-tree定理做法)
- 【BZOJ 1016】[JSOI2008]最小生成树计数 基尔霍夫矩阵||暴力
- [BZOJ1016]JSOI2008最小生成树计数 |kruskal|乘法原理|dfs
- bzoj1016: [JSOI2008]最小生成树计数 MST+DFS
- 【BZOJ】1016 [JSOI2008]最小生成树计数 最小生成树+DFS
- bzoj1016: [JSOI2008]最小生成树计数
- BZOJ 1016: [JSOI2008]最小生成树计数 kruskal dfs
- BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索
- 【bzoj1016】 JSOI2008—最小生成树计数
- 【BZOJ 1016】[JSOI2008]最小生成树计数(搜索+克鲁斯卡尔)
- 【最小生成树】BZOJ1016: [JSOI2008]最小生成树计数
- 【BZOJ1016】【JSOI2008】最小生成树计数 & 【BZOJ1543】生成树计数 (kruskal+matrix_tree定理)
- 【bzoj1016】[JSOI2008]最小生成树计数
- BZOJ1016 [JSOI2008]最小生成树计数
- bzoj1016: [JSOI2008]最小生成树计数
- bzoj 1016: [JSOI2008]最小生成树计数 (矩阵树定理+最小生成树)
- 【bzoj1016】[JSOI2008]最小生成树计数
- Bzoj1016: [JSOI2008]最小生成树计数