【题目链接】: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. jdk目录详解及其使用方法

    jdk目录详解 jdk目录详解 JDK(Java Development Kit,Java开发包,Java开发工具)是一个写Java的applet和应用程序的程序开发环境.它由一个处于操作系统层之上的 ...

  2. 【iOS开发系列】颜色渐变

    记录: //Transparent Gradient Layer - (void) insertTransparentGradient { UIColor *colorOne = [UIColor c ...

  3. Instant Client 配置

    Instant Client Download 选择  Instant Client for Microsoft Windows (32-bit)  由于PL/SQL Developer 不支持64b ...

  4. springmvc hibernate整合

    今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多 了,Spring-Security的就留在下一篇吧,这篇主 ...

  5. iOS_03_为什么选择ios开发

    为什么选择ios开发 为什么要选择移动开发 * 手机将是人类最离不开的设备之一,硬件软件参数也越来越强,应用需求量剧增. * 移动互联(就是将移动通信和互联网二者结合起来)发展迅速,各大公司都对移动互 ...

  6. 【习题 3-2 UVA - 1586】Molar mass

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟. 主要是找那个数字. [代码] #include <bits/stdc++.h> using namespace ...

  7. iOS ASIHTTPRequest

    ASIHTTPRequest对CFNetwork API进行了封装,并且使用起来非常简单,用Objective-C编写,可以很好的应用在Mac OS X系统和iOS平台的应用程序中.ASIHTTPRe ...

  8. stm32四种输入

    1.          上拉输入(GPIO_Mode_IPU)   上拉输入就是信号进入芯片后加了一个上拉电阻,再经过施密特触发器转换成0.1信号,读取此时的引脚电平为高电平:   2.       ...

  9. 【例题3-4 UVA - 340】Master-Mind Hints

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 这里出现了没有在相同位置的只能唯一配对. 就是说 3322 2234 这种情况. 只有3个weak pair. 即key[1]=a[ ...

  10. Gora官方范例 分类: C_OHTERS 2015-01-29 16:14 632人阅读 评论(0) 收藏

    参考官方文档:http://gora.apache.org/current/tutorial.html 项目代码见:https://code.csdn.net/jediael_lu/mygoradem ...