BZOJ 1016 【JSOI2008】 最小生成树计数
2016-06-11 15:38
549 查看
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,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过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
8这一次居然自己想出来了一道还算比较难的题,心里好开心O(∩_∩)O~~
这道题用到了最小生成树的几个性质。第一,最小生成树每种边权的边数量一定。第二(由第一点可得),当一个图有多个最小生成树时,只可能由一条边替换掉一条等边权的边来得到一颗新的最小生成树。所以,注意到题目中的一个条件:
具有相同权值的边不会超过10条。
所以我们就非常地开心。因为这样就可以做了。我们把边按权值排序,然后对于每一块权值相同的边搜索哪些边要选,再统计一下方案数就可以AC辣!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 5010 #define INF (1LL<<50) #define mod 31011 using namespace std; typedef long long llg; struct data{ int u,v,x; bool operator < (const data &h)const{return x<h.x;} }s[maxn]; struct dat1{ int l,r,x; dat1(int a=0,int b=0,int c=0):l(a),r(b),x(c){}; }ss[maxn]; int n,m,fa[maxn],ls,la[maxn],w[maxn]; llg ans=INF,a1,now,aa=1; bool ww[maxn]; int getint(){ int w=0,q=0; char c=getchar(); while((c<'0'||c>'9')&&c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} inline void work(){ now=0;int k=0; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1,u,v;i<=m;i++) if(ww[i]){ u=s[i].u;v=s[i].v; if(find(u)!=find(v)){ now+=s[i].x; k++; fa[find(u)]=find(v); } } if(k!=n-1) return; if(now<ans) ans=now,a1=1; else if(now==ans) a1++; } void dfs(int res,int now,int dd){ if(now==dd+1){ work();return; } if(res){ ww[now]=1; dfs(res-1,now+1,dd); } if(dd-now+1>res){ ww[now]=0; dfs(res,now+1,dd); } } int main(){ n=getint();m=getint(); for(int i=1;i<=m;i++){ s[i].u=getint();s[i].v=getint(); s[i].x=getint(); } sort(s+1,s+m+1); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1,u,v;i<=m;i++){ w[i]=w[i-1]; ww[i]=1; la[i]=i; u=s[i].u;v=s[i].v; if(s[i-1].x==s[i].x) la[i]=la[i-1]; if(find(u)!=find(v)){ now+=s[i].x; w[i]++; fa[find(u)]=find(v); } if(la[i]!=i && s[i+1].x!=s[i].x) ss[++ls]=dat1(la[i],i,w[i]-w[la[i]-1]); } for(int i=1;i<=ls;i++){ ans=INF; dfs(ss[i].x,ss[i].l,ss[i].r); for(int j=ss[i].l;j<=ss[i].r;j++) ww[j]=1; aa*=a1; aa%=mod; } ans%=mod; aa%=mod; printf("%lld",aa); return 0; }
相关文章推荐
- Ajax之在SSM中的json用法
- JS获得本月的第一天和最后一天
- javascript中的基本数据类型以及类型检测的几种方法
- JavaScript的运算符
- 星期几的不同脚本写法(推荐)和JS年月日格式
- Ajax之在s2sh中的json用法
- JS定时器使用,定时定点,固定时刻,循环执行详解
- js 光标位置
- js unicode转中文
- 常用js 时间函数
- 做一名合格的前端开发工程师(12篇)——第一篇 Javascript加载执行问题探索
- Windows下安装和使用UglifyJS
- javascript原型链
- js取小数后两位
- js函数定义 参数只要写名称就可以了
- 构建WebIM聊天程序
- js调用的注意项
- js 排序
- js note 2
- js 中时间戳转换格式化日期