博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JSOI2008 最小生成树计数
阅读量:5253 次
发布时间:2019-06-14

本文共 2768 字,大约阅读时间需要 9 分钟。

Time Limit: 1 Sec Memory Limit: 162 MB

Description

  现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的

最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。

Input

第一行包含两个数,\(n\)\(m\),其中\(1\leq n\leq100\); \(1\leq m\leq1000\); 表示该无向图的节点数和边数。每个节点用1~n的整数编号。

接下来的m行,每行包含两个整数:\(a\),\(b\),\(c\),表示节点\(a\),\(b\)之间的边的权值为\(c\),其中\(1\leq c \leq 1,000,000,000\)。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过\(10\)条。

Output

输出不同的最小生成树有多少个。你只需要输出数量对\(31011\)的模就可以了。

Sample Input

4 61 2 11 3 11 4 12 3 22 4 13 4 1

Sample Output

8

Solution

这道题目的思路其实也比较新颖,还是要多练习练习。做题目还是要逐一分析所有性质啊。

我们可以发现,对于同一种边权,在任何的最小生成树中的数量都是一定的。这个挺好证的,就不详细说了。而且事实上,同一种边权在所有最小生成树里面的作用都是一样的——它们连接成联通快一定是一样的。

我们可以从Kruskal的正确性上连看出这个性质。从小到大排序,逐一加边,这样一种边权全都加完,已经尽量地连接上了这个边权所能连接上的尽量多的联通快了,这个已经是这个边权的极限了。我们假如同一种边权有两种不同的连接方法能把不同的两组点连接起来,那么我们显然可以合并一下,得到更大的联通块。因此,同一种边权在所有最小生成树永远都是连接同一组点的。

同时,不用的边权的作用也是相互独立的。这个性质非常显然,因为上面已经得到,之前的比它小的边权只能得到一个联通快,那么这一个边权就可以直接把那个联通块视为一个点,然后找他自己的东西了。

那么我们就得到了做法:先跑一边Kruskal,求出每一种边权的使用次数。然后在每一种边权内部,直接搜索有多少种方案。因为同一种边权不超过10个,所以复杂度得到了保证。

不过这里深搜需要回溯,所以我们的并查集不能路径压缩,不然不方便撤销。直接按秩合并,可以保证复杂度的\(\log\)

#include
#include
#include
#include
using namespace std;#define lowbit(x) ((x)&(-(x)))#define REP(i,a,n) for(register int i=(a);i<=(n);++i)#define PER(i,a,n) for(register int i=(a);i>=(n);--i)#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)#define dbg(...) fprintf(stderr,__VA_ARGS__)namespace io{ const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr; #define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++) inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;} inline void putc(char x){*oS++=x;if(oS==oT)flush();} template
inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;} template
inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);} struct Flusher_{~Flusher_(){flush();}}io_flusher_;}//orz laofudasuanusing io::read;using io::putc;using io::write;typedef long long ll;typedef unsigned long long ull;template
inline bool SMAX(A&x,const B&y){return y>x?x=y,1:0;}template
inline bool SMIN(A&x,const B&y){return y
>1;if(x<=b[mid])r=mid;else l=mid+1;}return l;}inline void LSH(){ sort(G+1,G+m+1);for(register int i=1;i<=m;++i)if(i==1||G[i].z!=G[i-1].z)b[++dis]=G[i].z; for(register int i=1;i<=m;++i)G[i].z=Bound(G[i].z),g[G[i].z][++g[G[i].z][0]]=i;}int fa[N],num[N];inline int Find(int x){while(fa[x]!=x)x=fa[x];return x;}inline void Union(int x,int y){x=Find(x),y=Find(y);if(num[x]

转载于:https://www.cnblogs.com/hankeke/p/9835118.html

你可能感兴趣的文章
CF E2 - Array and Segments (Hard version) (线段树)
查看>>
Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化
查看>>
SIGPIPE并产生一个信号处理
查看>>
CentOS
查看>>
Linux pipe函数
查看>>
java equals 小记
查看>>
爬虫-通用代码框架
查看>>
2019春 软件工程实践 助教总结
查看>>
YUV 格式的视频呈现
查看>>
Android弹出框的学习
查看>>
现代程序设计 作业1
查看>>
在android开发中添加外挂字体
查看>>
Zerver是一个C#开发的Nginx+PHP+Mysql+memcached+redis绿色集成开发环境
查看>>
多线程实现资源共享的问题学习与总结
查看>>
Learning-Python【26】:反射及内置方法
查看>>
torch教程[1]用numpy实现三层全连接神经网络
查看>>
java实现哈弗曼树
查看>>
转:Web 测试的创作与调试技术
查看>>
python学习笔记3-列表
查看>>
程序的静态链接,动态链接和装载 (补充)
查看>>