【题目链接】: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. 洛谷——P1598 垂直柱状图

    https://www.luogu.org/problem/show?pid=1598 题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过72个字符),然后用柱状图输出每个字 ...

  2. COGS——C66. [HAOI2004模拟] 数列问题

    http://www.cogs.pro/cogs/problem/problem.php?pid=66 ★☆   输入文件:dfs3.in   输出文件:dfs3.out   简单对比 时间限制:1 ...

  3. ORACLE 11G R2 DG_BROKER 之SWITCH OVER

      官网:http://docs.oracle.com/cd/B12037_01/server.101/b10822/cli.htm 这个是有必要看一下. 注意本人已经完毕一次SWITCHOVER 所 ...

  4. 老李的菜园 mysql 自定义函数

    新建: Create function function_name(参数列表)returns返回值类型 函数体 函数名,应该合法的标识符,并且不应该与已有的关键字冲突. 一个函数应该属于某个数据库,可 ...

  5. C语言结构体的字节对齐原则

    为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...

  6. 【BZOJ 3156】防御准备

    [链接] 链接 [题意] 在这里输入题意 [题解] 把a倒过来 设f[i]表示在i放一个防御塔的最小花费; 我们如果从j转移过来 就表示j+1..i-1这一段放人偶. s[i] = 1 + 2 + . ...

  7. 利用a标签导出csv文件

    原文 简书原文:https://www.jianshu.com/p/a8687610cda3 大纲 1.需求分析 2.通过a标签实现文件导出 3.实现方式 1.需求分析 导出文件,使用最多的方式还是服 ...

  8. 读Effective Objective-C [提高OC代码质量总结笔记第一篇:熟悉OC]

    一.OC特性 OC 为 C 语言添加了面向对象特性,是其超集; OC 使用动态绑定的消息结构,也就是,在运行时才会检查对象类型; 接收一条消息后,究竟应执行何种代码,由运行期环境来决定,而非 编译器; ...

  9. 黑马程序猿-assign、retain、release、nonatomic、atomic、strong、weak

    都是用于修饰@property声明的变量 assign:用于非oc对象类型,表示直接赋值(默认值) retain:用于mrc中,用于类属性中有oc对象的情况,表示先推断赋值的对象是否和实例对象变量的值 ...

  10. jquery-12 jquery常用动画效果有哪些

    jquery-12 jquery常用动画效果有哪些 一.总结 一句话总结:jquery可以用户animate()自定义动画,也可以slide和fade系列方法来设置动画. 1.动画效果如何设置执行时间 ...