【题目链接】: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. 关于Promise的详细总结

    1. 异步回调 1.1 回调地狱 在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的回调地狱 1.2 并行结果 如果几个异步操作之间并没有前后顺序之分,但需要等多个异步操作都完 ...

  2. 【Codeforces Round #431 (Div. 2) C】From Y to Y

    [链接]点击打开链接 [题意] 让你构造一个大小最多为10W的字符multiset. 你进行n-1次操作; 每次操作,从set中取出两个字符串,一开始单个字符被认为是字符串. 然后把它们连接在一起. ...

  3. [Angular] Implement a custom form component by using control value accessor

    We have a form component: <label> <h3>Type</h3> <workout-type formControlName=& ...

  4. MWPhotoBrowser 属性详解 和代理解释

    --------0.MWPhoto简单属性解释---------------- MWPhoto *photo = [MWPhoto photoWithURL:[NSURL URLWithString: ...

  5. [React Intl] Render Content with Markup Using react-intl FormattedHTMLMessage

    In this lesson, we’ll use the react-intl FormattedHTMLMessage component to display text with dynamic ...

  6. iOS_04_学习ios开发的准备

    学习ios开发的准备 * 英语水平:看懂26个英文字母. * 计算机专业:不要求计算机专业,但得有脑子. * 学习态度:积极思考.积极动手.能吃苦.有兴趣. * 编程语言:C语言.C++(可选).Ob ...

  7. POJ 1679 The Unique 次最小生成树 MST

    http://poj.org/problem?id=1679 题目大意: 给你一些点,判断MST(最小生成树)是否唯一. 思路: 以前做过这题,不过写的是O(n^3)的,今天学了一招O(n^2)的,哈 ...

  8. 【Codeforces Round #435 (Div. 2) B】Mahmoud and Ehab and the bipartiteness

    [链接]h在这里写链接 [题意] 让你在一棵树上,加入尽可能多的边. 使得这棵树依然是一张二分图. [题解] 让每个节点的度数,都变成二分图的对方集合中的点的个数就好. [错的次数] 0 [反思] 在 ...

  9. [Nuxt] Build a Navigation Component in Vue.js and Use in a Nuxt Layout

    You can isolate parts of templates you want to re-use into components, but you can also reuse those ...

  10. PHP通用非法字符检测函数集锦

    <? // [变量定义规则]:‘C_’=字符型,‘I_’=整型,‘N_’=数字型,‘L_’=布尔型,‘A_’=数组型 // ※CheckMoney($C_Money) 检查数据是否是 99999 ...