总结:此类题需要耐心观察规律,大胆猜想,然后证明猜想,得到有用的性质,然后解答。 简单的说:找隐含性质。

传送门:http://61.187.179.132/JudgeOnline/problem.php?id=1016

题意:n个点m条边的图,问其最小生成树的个数(只要有一条边不同,就算不同)。n<100, m<1000 权值c < 10^9, 其中权相同的边的数量不会超过10条。

思路:

经过观察思考,得到以下结论:

任意两个最小生成树,将其所有边的边长排序后,将得到完全相同的结果。

意思是:只能用相同长度的边来代替,借此得到不同的最小生成树。

又因为每种权相同的边数不超过10,则可以用以下方法:

首先,生成一个最小生成树,得到其包含的所有权值以及数量。

其次,将其中某种权值的边删除,然后在图中取出所有权值相同的边, 状态压缩暴力匹配。得到这种边可以组合的方案数。

将所有权值的边的方案数相乘,就得到答案。

时间复杂度:MlogM + n(2^10*n) + M

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define mod 31011
#define N 200 struct Edge{
int a, b, c;
bool operator < (const Edge &b) const {
return c < b.c;
}
}e[], mintre[]; struct BCJ{
int fa[N];
void init(int n) {
for (int i = ; i <= n; i++) {
fa[i] = i;
}
}
int find(int u) {
return fa[u]== u ? fa[u] : fa[u] = find(fa[u]);
}
void unin(int u, int v) {
fa[find(v)] = find(u);
}
}b; int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = ; i < m; i++) {
scanf("%d%d%d", &e[i].a, &e[i].b, &e[i].c);
}
sort(e, e+m);
int top = ;
b.init(n);
for (int i = ; i < m; i++) {
if (b.find(e[i].a) != b.find(e[i].b)) {
b.unin(e[i].a, e[i].b);
mintre[top++] = e[i];
}
}
if (top != n-) {
puts("");
continue;
} int minp = ;
int ep = ;
int ans = ;
while (true) {
if (minp == top || ep == m) break;
int nowc = mintre[minp].c;
//printf("nowc = %d\n", nowc);
BCJ nowTong;
nowTong.init(n);
for (int i = ; i < top; i++) {
if (mintre[i].c != nowc) {
nowTong.unin(mintre[i].a, mintre[i].b);
}
} int edgeNum = ;
while (ep < m && e[ep].c < nowc) ep++;
while (ep < m && e[ep].c == nowc) {
edgeNum++;
ep++;
} int nownum = ;
while (minp < top && mintre[minp].c == nowc) {
nownum++;
minp++;
}
if (edgeNum == nownum) continue;
int end = (<<edgeNum);
int nowans = ;
BCJ tmpTong;
for (int i = ; i < end; i++) {
int tmpi = i;
int num = ;
while (tmpi) {
num += (tmpi&);
tmpi>>=;
}
if (num != nownum) continue; tmpTong = nowTong;
tmpi = i;
int unintime = ;
for (int j = ep-; e[j].c == nowc; j--) {
if (tmpi&) {
if (tmpTong.find(e[j].a) != tmpTong.find(e[j].b)) {
unintime++;
tmpTong.unin(e[j].a, e[j].b);
}
}
tmpi>>=;
}
if (unintime == nownum) {
nowans++;
}
}
ans *= nowans;
ans %= mod;
}
printf("%d\n", ans);
}
return ;
}

大视野 1016: [JSOI2008]最小生成树计数(最小生成树)的更多相关文章

  1. BZOJ1016:[JSOI2008]最小生成树计数(最小生成树,DFS)

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

  2. [BZOJ1016][JSOI2008]最小生成树计数 最小生成树 搜索

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1016 做这道题之前需要知道一些结论,同一个图的最小生成树中相同权值的边的个数是不会变的,如 ...

  3. 【BZOJ1016】【Luogu P4208】 [JSOI2008]最小生成树计数 最小生成树,矩阵树定理

    蛮不错的一道题,遗憾就遗憾在数据范围会导致暴力轻松跑过. 最小生成树的两个性质: 不同的最小生成树,相同权值使用的边数一定相同. 不同的最小生成树,将其都去掉同一个权值的所有边,其连通性一致. 这样我 ...

  4. $bzoj1016-JSOI2008$ 最小生成树计数 最小生成树 $dfs/matrix-tree$定理

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

  5. BZOJ1016最小生成树计数 最小生成树 + 排列组合

    @[最小生成樹, 排列組合] Discription 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的 最小生成树.(如果两颗最小生成树中至少有一条边不 ...

  6. 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 9851  Solved: 4318[Submi ...

  7. 【BZOJ】【1016】【JSOI2008】最小生成树计数

    Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的 ...

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

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

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

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

随机推荐

  1. mysql 在线添加字段

    使用工具pt-online-schema-change #! /bin/bash stime=`date +%s` echo "增加字段开始测试时间为:`date +%H:%M:%S`&qu ...

  2. 如何用纯 CSS 创作一颗逼真的土星

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/EpbaQX 可交互视频 ...

  3. for_each_node(node)

    遍历各个pg_data_t节点. 1.定义在include/linux/nodemask.h中 /* * Bitmasks that are kept for all the nodes. */ en ...

  4. poj 1017 装箱子问题 贪心算法

    题意:有1*1到6*6的的东西,需要用6*6的箱子将它们装起来.问:至少需要多少个6*6箱子 思路: 一个瓶子怎么装东西最多?先装石头,在装沙子,然后装水. 同样放在本题就是先装6*6然后5*5... ...

  5. Linux学习-透过 systemctl 管理服务

    透过 systemctl 管理单一服务 (service unit) 的启动/开机启动与观察状态 一般来说,服务的启动有两个阶段,一 个是『开机的时候设定要不要启动这个服务』, 以及『你现在要不要启动 ...

  6. IE6 单文件绿色版

    IE6单文件绿色版,可以直接运行,无需安装,完美兼容Win10(自带2016年1月更新). https://www.lanzous.com/i3w7dej

  7. 在Ubuntu中打开pycharm步骤:

    在pycharm的bin文件夹中打开终端,包含pycharm.sh文件的,输入“sh pycharm.sh",如下图所示: 创建工程和windows环境下相同. 结束关掉pycharm 终端 ...

  8. 光学字符识别OCR-6 光学识别

    经过前面的文字定位和文本切割,我们已经能够找出图像中单个文字的区域,接下来可以建立相应的模型对单字进行识别. 模型选择         在模型方面,我们选择了深度学习中的卷积神经网络模型,通过多层卷积 ...

  9. SpringMVC 页面传递参数到controller的五种方式

    一共是五种传参方式: 一:直接将请求参数名作为Controller中方法的形参 public  String login (String username,String password)   : 解 ...

  10. Thinkphp5.1源码阅读

    主要流程 1 \public\index.php require __DIR__ . '/../thinkphp/start.php'; \thinkphp\start.php require __D ...