【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1016

【题意】

【题解】

/*
两个最小生成树T和T';
它们各个边权的边的数目肯定是一样的;
且相同边权的边;
那些边所形成的联通性是一样的; 可以考虑T和T'的形成;
比如说一开始
T和T'都是空的;
然后把边按边权从小到大排序后
找到的第一种边权的边权为
v1
且bian[left..right]都是这种边权的边; 然后假设T是我们正常用卡鲁斯卡尔算法搞出来的最小生成树;
那么T在这个阶段肯定会在这right-left+1条边中选择x条边; 那么这个时候我们再想想T'要怎么选?
假设我们选y条边
这里我们分类讨论一下
假如y>x,
这种情况是不可能的;
因为如果y可以大于x;
那就说明T还可以再加一条边权最小的边v1联通更多的分量;
而我们在做克鲁斯卡尔的时候已经保证了不能添加更多的分量;
所以可以排除;
假如y<x
这种情况也是不可能的;
假设我们少选了一条边
那么这条边链接的两个分量必然是要用更大的边权来链接;
这就不符合最小生成树了;
所也可以排除;
综上可知
x==y;
这里所选的y条边的各个节点的连通性必然和x条边的联通性一样;
因为如果不一样的话,
那么哪里不一样呢??
->假设在T'中相对于T有两个分量没有连通在一起,那么你可以选择T中连接这两个分量的
边啊。而且因为是升序排的,所以肯定连了更优啊;
但是显然不可能再有这样的连法了,因为T是正确的最小生成树;
你如果能找到这样的连法的话,就说明T是不正确的了;
这就矛盾了;
根据上面的推导可知;
每个最小生成树;
出现的不同边权的种类是一样的,且各种边权的数目是确定的;
而且只要边权的数目确定了,这个边权造成的连通性的变化都是一样的; 所以我们只要枚举对于每一种边权,可以用哪些连着不同节点的边,但边权和它相同的边交换一下
一开始做的最小生成树的边就好了;
比如第i种边权的边v[i],出现的次数为numv[i];
然后在用克鲁斯卡尔算法算出的最小生成树中v[i]出现的次数为k;
则从这numv[i]条边中选出k条边来,看看是不是这k条边中每条边都能对联通量贡献;(如果有一条边在做
的过程中边的两段链接的联通量已经是在一起的了,就退出,表示不行);
因为要回溯,所以这里的并查集不能加状态压缩。
当然n也不大就是了;
因为有说同边权的边的数目不超过10,所以2^10是可以接受的.
搜一波;
然后用乘法原理乘起来就好;
*/

【完整代码】

#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x) typedef pair<int, int> pii;
typedef pair<LL, LL> pll; const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
const double pi = acos(-1.0);
const int M = 1100;
const int N = 110;
const int MOD = 31011; struct abc
{
int x, y,z;
}; int n, m,f[N],tot = 0,tot1 = 0,num[M],sum = 0,ans = 1;
abc bian[M]; bool cmp1(abc a, abc b)
{
return a.z < b.z;
} int ff(int x)
{
if (f[x] == x) return x;
else
return ff(f[x]);
} void dfs(int l, int r, int now)
{
if (now == num[tot])
{
sum++;
return;
}
if (l > r) return;
int x = bian[l].x, y = bian[l].y;
int r1 = ff(x), r2 = ff(y);
//这里f[r1]==r1,f[r2]==r2;
if (r1 != r2)
{
f[r1] = r2;
dfs(l + 1, r, now + 1);
f[r1] = r1, f[r2] = r2;
}
dfs(l + 1, r, now);
} int main()
{
//freopen("F:\\rush.txt", "r", stdin);
rei(n), rei(m);
rep1(i, 1, m)
rei(bian[i].x), rei(bian[i].y), rei(bian[i].z);
sort(bian + 1, bian + 1 + m,cmp1);
rep1(i, 1, n)
f[i] = i;
rep1(i, 1, m)
{
int l = i, r = i;
while (r + 1 <= m && bian[r + 1].z == bian[l].z) r++;
tot1++;
rep1(j, l, r)
{
int x = bian[j].x, y = bian[j].y;
int r1 = ff(x), r2 = ff(y);
if (r1 != r2)
{
f[r1] = r2;
tot++;
num[tot1]++;
}
}
i = r;
}
if (tot != n - 1)
return puts("0"), 0;
rep1(i, 1, n)
f[i] = i;
tot = 0;
rep1(i, 1, m)
{
int l = i, r = i;
while (r + 1 <= m && bian[r + 1].z == bian[l].z) r++;
tot++;
if (num[tot] == 0)
{
i = r;//。。。。。。bug点
continue;
}
sum = 0;
dfs(l, r, 0);
ans = (ans*sum) % MOD;
rep1(j, l, r)
{
int r1 = ff(bian[j].x), r2 = ff(bian[j].y);
if (r1 != r2)
f[r1] = r2;
}
i = r;
}
printf("%d\n", ans);
return 0;
}

【BZOJ 1016】[JSOI2008]最小生成树计数(搜索+克鲁斯卡尔)的更多相关文章

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

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

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

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

  3. [BZOJ]1016 JSOI2008 最小生成树计数

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

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

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

  5. BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)

    题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...

  6. bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 就是缩点,每次相同权值的边构成的联通块求一下matrix tree.注意gauss里的 ...

  7. BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理

    考虑从小往大加边,然后把所有联通块的生成树个数计算出来. 然后把他们缩成一个点,继续添加下一组. 最后乘法原理即可. 写起来很恶心 #include <queue> #include &l ...

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

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

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

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 6200  Solved: 2518[Submit][St ...

随机推荐

  1. vue 键盘回车事件导致页面刷新的问题,路由多了一个问号

    问题: <el-form @submit.native.prevent> <el-form-item > <el-input @keyup.enter.native=&q ...

  2. JSP中的EL表达式详细介绍

    一.JSP EL语言定义 EL 提供了在 JSP 脚本编制元素范围外使用运行时表达式的功能.脚本编制元素是指页面中能够用于在 JSP 文件中嵌入 Java 代码的元素.它们通常用于对象操作以及执行那些 ...

  3. Cscope how to support java and c++

    Cscope 首先在文件夹下建立cscope索引文件 find -name '*.c' > cscope.file cscope -Rbkq 这个命令会生成三个文件:cscope.out, cs ...

  4. treap-名次树-树堆

    #include <cstring> #include <cstdio> #include <cstdlib> using namespace std; struc ...

  5. Android Material风格的应用(五)--CollapsingToolbar

    Collapsing Toolbar Android Material风格的应用(一)--AppBar TabLayoutAndroid Material风格的应用(二)--RecyclerViewA ...

  6. SpringBoot学习:获取yml和properties配置文件的内容(转)

    项目下载地址:http://download.csdn.net/detail/aqsunkai/9805821 (一)yml配置文件: pom.xml加入依赖: <!-- 支持 @Configu ...

  7. 推荐一下《聊聊JVM》的专栏

    依照惯例新开了一个专栏后要单推一下.推荐一下<聊聊JVM的专栏>,网上关于JVM的文章太多,这个专栏希望能在已有的资料的基础上写出点新意,对一些重要的概念归纳总结,说说自己的观点.理解和实 ...

  8. 【Codeforces Round #439 (Div. 2) B】The Eternal Immortality

    [链接] 链接 [题意] 求b!/a!的最后一位数字 [题解] b-a>=20的话 a+1..b之间肯定有因子2和因子5 答案一定是0 否则暴力就好 [错的次数] 在这里输入错的次数 [反思] ...

  9. js进阶ajax函数封装(匿名函数作为参数传递)(封装函数引入文件的方式非常好用)

    js进阶ajax函数封装(匿名函数作为参数传递)(封装函数引入文件的方式非常好用) 一.总结 2.匿名函数作为参数传递 二.js进阶ajax函数封装 ajax1.js function ajax(ur ...

  10. 魔兽争霸war3心得体会(三):UD内战

    最近,经常匹配到UD内战.有输有赢,有的时候,自己双矿经济,人口优势巨大,却很遗憾地输掉比赛. 本文,简要分析下 对战过程. 前期狗流开局, 5只狗,一只出去骚扰,攻击商店,防止对方科技蜘蛛骚扰我.二 ...