【BZOJ 1016】[JSOI2008]最小生成树计数(搜索+克鲁斯卡尔)
【题目链接】: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]最小生成树计数(搜索+克鲁斯卡尔)的更多相关文章
- BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )
不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...
- [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】
题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...
- [BZOJ]1016 JSOI2008 最小生成树计数
最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...
- bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】
有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...
- BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)
题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...
- bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 就是缩点,每次相同权值的边构成的联通块求一下matrix tree.注意gauss里的 ...
- BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理
考虑从小往大加边,然后把所有联通块的生成树个数计算出来. 然后把他们缩成一个点,继续添加下一组. 最后乘法原理即可. 写起来很恶心 #include <queue> #include &l ...
- 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)
1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...
- 1016: [JSOI2008]最小生成树计数
1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 6200 Solved: 2518[Submit][St ...
随机推荐
- Jszip的使用和打包下载图片
因为canvas总结到后面又想到了jszip的一些事情,那就索性也回去看看吧.试过,至少谷歌和火狐都是支持jszip的. 1. jszip的使用 官方文档说的很清楚了,而且也有读取zip文件.生成z ...
- RGB颜色转换为多种颜色工具、公式
http://www.easyrgb.com/index.php?X=CALC#Result http://www.easyrgb.com/index.php?X=MATH
- Android Gradle统一依赖管理
目的: 避免在依赖包出新版本时,需要对每个module中的build.gradle文件都进行修改(如appcompat-v7包),使用这种方式即只需一次修改. 方法一 在项目的根目录创建一个gradl ...
- python 命令行:help(),'more'不是内部或外部命令,也不是可运行的程序或批处理文件
Python下使用help(dict),显示'more'不是内部或外部命令,也不是可运行的程序或批处理文件,该如何处理? 环境变量设置的问题,进入 Path 的环境变量设置界面,将;%SystemRo ...
- POJ 1679 The Unique 次最小生成树 MST
http://poj.org/problem?id=1679 题目大意: 给你一些点,判断MST(最小生成树)是否唯一. 思路: 以前做过这题,不过写的是O(n^3)的,今天学了一招O(n^2)的,哈 ...
- OC学习篇之---Foundation框架中的NSString对象和NSMutableString对象
今天在在来继续看一下Foundation框架中的常用对象:NSString和NSMutableString 在OC中NSString对象是不可变的,和Java中的String一样的,而NSMutabl ...
- VS无法访问IIS元数据库 您没有足够的特权访问计算机上的IIS网站
进入windows\regedit.exe下的HKEY_CRRENT_USER\Software\Microsoft\Windows\CurrentVersion\Exploer\User Shell ...
- DMA 如何查看它有没有传输完成 传输完成再开启
摘自:https://blog.csdn.net/zzwdkxx/article/details/9026173 /////////////////////////////////////////// ...
- 关于用strace工具定位vrrpd进程有时会挂死的bug
只做工作总结备忘之用. 正在烧镜像,稍总结一下进来改bug遇到的问题. 一个项目里要用到L3 switch的nat,vrrp功能,但实地测试中偶然出现write file挂死的情况,但不是必现.交付在 ...
- 中小研发团队架构实践之分布式协调器.Net版ZooKeeper
原文:中小研发团队架构实践之分布式协调器.Net版ZooKeeper 一.ZooKeeper是什么 Apache ZooKeeper是由Apache Hadoop的子项目发展而来,于2010年11月 ...