描述


http://www.lydsy.com/JudgeOnline/problem.php?id=1016

给出一张图,其中具有相同权值的边的数目不超过10,求最小生成树的个数.

分析


生成树的计数有一个什么什么算法...

我真的企图研究了...但是智商捉急的我实在看不懂论文...

所以最后还是写了暴力...

当然暴力也要靠正确的姿势的.

首先来看一个结论:

同一张图的所有最小生成树中,边权值相同的边的数目是一定的.

也就是说,假如某一张图的某一棵最小生成树由边权值为1,1,2,2,2,3的边组成,那么这张图的所有其他最小生成树也都由六条权值分别为1,1,2,2,2,3的边组成.

至于证明,我们可以用数学归纳法.

1.以上结论对与n=2的情况显然成立.

2.假设对于n=k的情况以上结论成立即k个节点的最小生成树满足相同权值的边的数目一定.那么对于n=k+1的情况,需要加一条边将第k+1个点连起来,因为生成树是最小的,所以所加的边的权值是一定的,而之前的k-1条边(连接之前的k个点的边)各权值的边的数目也是一定的,所以最终各权值的边的数目是一定的.

有了这样的一个结论,又因为相同权值的边的数目不超过10,所以我们就可以利用暴力dfs+乘法原理,统计每一种权值的边的选择的方案数,然后相乘即可.

 #include <bits/stdc++.h>
using namespace std; const int maxn=+,maxm=+,mod=;
struct edge{
int u,v,w;
edge(){}
edge(int u,int v,int w):u(u),v(v),w(w){}
bool operator < (const edge &a) const { return w<a.w; }
}g[maxm];
int n,m,cnt,sum,ans=;
int a[maxm],b[maxm],ect[maxm],f[maxn];
inline int read(int &x){x=;int k=;char c;for(c=getchar();c<''||c>'';c=getchar())if(c=='-')k=-;for(;c>=''&&c<='';c=getchar())x=x*+c-'';return x*=k;}
inline int find(int x){return x==f[x]?x:find(f[x]);}
void dfs(int s,int t,int rem){
if(rem==){
sum++;
return;
}
for(int i=s;i-+rem<=t;i++){
int fv=find(g[i].v),fu=find(g[i].u);
if(fu!=fv){
int F=f[fu];
f[fu]=fv;
dfs(i+,t,rem-);
f[fu]=F;
}
}
}
inline void solve(){
int i,j;
for(i=,j=;i<=m&&j<n;i++){
int fu=find(g[i].u),fv=find(g[i].v);
if(fu!=fv){
f[fu]=fv;
ect[b[i]]++;
j++;
}
}
if(j<n){
puts("");
return;
}
for(int i=;i<=n;i++) f[i]=i;
for(i=;i<=cnt;i++){
sum=;
dfs(a[i],a[i+]-,ect[i]);
for(int j=a[i];j<a[i+];j++){
int fu=find(g[j].u),fv=find(g[j].v);
if(fu!=fv) f[fu]=fv;
}
ans=(ans*sum)%mod;
}
printf("%d\n",ans);
}
inline void init(){
read(n); read(m);
for(int i=;i<=n;i++) f[i]=i;
for(int i=,u,v,w;i<=m;i++){
read(u); read(v); read(w);
g[i]=edge(u,v,w);
}
sort(g+,g++m);
for(int i=;i<=m;i++){
if(g[i].w!=g[i-].w) a[++cnt]=i;
b[i]=cnt;
}
a[cnt+]=m+;
}
int main(){
init();
solve();
return ;
}

1016: [JSOI2008]最小生成树计数

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4666  Solved: 1890
[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,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

Output

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

Sample Input

4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1

Sample Output

8

HINT

Source

BZOJ_1016_[JSOI2008]_最小生成树计数_(dfs+乘法原理)的更多相关文章

  1. BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...

  2. bzoj1016: [JSOI2008]最小生成树计数(kruskal+dfs)

    1016: [JSOI2008]最小生成树计数 题目:传送门 题解: 神题神题%%% 据说最小生成树有两个神奇的定理: 1.权值相等的边在不同方案数中边数相等  就是说如果一种方案中权值为1的边有n条 ...

  3. 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)

    1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...

  4. 【BZOJ】【1016】【JSOI2008】最小生成树计数

    Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的 ...

  5. [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】

    题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...

  6. bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】

    有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...

  7. BZOJ 1016 【JSOI2008】 最小生成树计数

    Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...

  8. 【BZOJ1016】【JSOI2008】最小生成树计数

    Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...

  9. BZOJ_1833_[ZJOI2010]_数字计数_(数位dp)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1833 统计\(a~b\)中数字\(0,1,2,...,9\)分别出现了多少次. 分析 数位dp ...

随机推荐

  1. Oracle PL/SQL 多重选择句

    Oracle中语句块的基本格式: declare --变量定义,初始化赋值. begin --变量的赋值,函数调用,if,while等. end: Oracle中的语句:关系运算符:= <> ...

  2. Registry uninstall values

    Original link: http://windowssucks.wordpress.com/win-registry-uninstall-values/ -------------------- ...

  3. const char*、char*、char* const、char[]、string的区别

    1.const char* p: p is a pointer to const char(char const* p 一样)   意思就是不能通过p指针来修改p指向的内容(但是内容可以修改). 2. ...

  4. win/linux 下使用 psutil 获取进程 CPU / memory / IO 占用信息

    psutil - A cross-platform process and system utilities module for Python 1. 安装 pip 安装即可. windows 下需要 ...

  5. preg_match_all, preg_match

    int preg_match(string $pattern, string $subject[, $arr][, int $flags]);$pattern 正则表达式$subject: 要搜索的字 ...

  6. java集合——进度1

    集合类的由来:    对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定.    就使用集合容器进行存储.    集合特点:1,用于存储对象的容器.2,集合的长度是可变的.3,集合中不可以存 ...

  7. IE浏览器窗口合并

    百度经验:如何在IE上设置多窗口合并为单窗口(可切换)?

  8. 数据结构———重载与模板(C++)

    相关信息 /* * * @subject 数据结构 * @author 信管1142班 201411671210 JJ lai * * @program 模板与重载 * */ 实验一: /* 要求如下 ...

  9. Ubuntu中PyCharm中字体设置

    在Ubuntu安装的PyCharm与Windows不同,除了Editor中的字体.配色需要设置外,文件操作栏(File--Edit--View--Navigate--Code--Refactor--- ...

  10. Android手势监听

    public class MainActivity extends Activity { /* * 要实现手指在屏幕上左右滑动的事件需要实例化对象GestureDetector,new * Gestu ...