1016: [JSOI2008]最小生成树计数
1016: [JSOI2008]最小生成树计数
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 6200 Solved: 2518
[Submit][Status][Discuss]
Description
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的
最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生
成树可能很多,所以你只需要输出方案数对31011的模就可以了。
Input
第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整
数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。
Output
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
Sample Input
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
Sample Output
/*
* @Author: LyuC
* @Date: 2017-09-07 21:48:20
* @Last Modified by: LyuC
* @Last Modified time: 2017-09-12 17:52:51
*/
/*
题意:现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道
这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则
这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方
案数对31011的模就可以了。 思路:每个最小生成树的相同权值的边数是相同的,并且连通性是相同的,只需要枚举每个
权值的相同连通性,并且是最小生成树中这个权值的个数的方案数,然后组合一下就行了
*/
#include <bits/stdc++.h> #define MAXN 105
#define MAXM 1005
#define mod 31011 using namespace std; struct Edge{
int u,v,w;
bool operator < (const Edge & other) const{
return w<other.w;
}
}edge[MAXM];
vector<Edge>v[MAXM];
int n,m;
int x,y,z;
int bin[MAXN];
int root[MAXN];
int vis[MAXM];//每种权值用到的数量
int sum;
int la;
int pos;
int res; inline int findx(int x){
int s=x;
while(x!=bin[x])
x=bin[x];
bin[s]=x;
return x;
} inline int Count(int x){
int s=;
while(x){
if(x%)
s++;
x/=;
}
return s;
} inline void init(){
for(int i=;i<=n;i++){
bin[i]=i;
root[i]=i;
}
memset(vis,,sizeof vis);
for(int i=;i<MAXM;i++)
v[i].clear();
res=;
pos=;
sum=;
} int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
init();
for(int i=;i<m;i++){
scanf("%d%d%d",&x,&y,&z);
edge[i].u=x;
edge[i].v=y;
edge[i].w=z;
}
sort(edge,edge+m);
//处理每种权值需要的边数
la=-;
for(int i=;i<m;i++){
if(edge[i].w!=la){
la=edge[i].w;
bool flag=false;
for(int j=i;edge[j].w==la;j++){
int fx=findx(edge[j].u);
int fy=findx(edge[j].v);
if(fx!=fy){
flag=true;
bin[fx]=fy;
vis[pos]++;
sum++;
}
v[pos].push_back(edge[j]);
}
pos++;
}
}
if(sum!=n-){
puts("");
return ;
}
for(int i=;i<pos;i++){//枚举每个阶段用到权值的边
if(vis[i]==) continue;
int tol=(<<v[i].size());
int cur=;//可以的方案
for(int j=;j<tol;j++){
if(Count(j)!=vis[i]) continue;
bool flag=true;
memcpy(bin,root,sizeof root);
for(int k=;k<v[i].size();k++){
if((j&(<<k))!=){//如果这条边存在
int fx=findx(v[i][k].u);
int fy=findx(v[i][k].v);
if(fx==fy){
flag=false;
break;
}else{
bin[fx]=fy;
}
}
}
if(flag==true)
cur++;
}
res=res*cur%mod;
memcpy(bin,root,sizeof root);
for(int j=;j<v[i].size();j++){
int fx=findx(v[i][j].u);
int fy=findx(v[i][j].v);
if(fx!=fy){
bin[fx]=fy;
}
}
memcpy(root,bin,sizeof bin);
}
printf("%d\n",res%mod);
return ;
}
1016: [JSOI2008]最小生成树计数的更多相关文章
- BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )
不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...
- 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)
1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...
- [BZOJ]1016 JSOI2008 最小生成树计数
最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...
- 【BZOJ】1016: [JSOI2008]最小生成树计数 深搜+并查集
最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小 ...
- 【BZOJ】1016: [JSOI2008]最小生成树计数(kruskal+特殊的技巧)
http://www.lydsy.com/JudgeOnline/problem.php?id=1016 想也想不到QAQ 首先想不到的是:题目有说,具有相同权值的边不会超过10条. 其次:老是去想组 ...
- [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】
题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...
- BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)
题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...
- 大视野 1016: [JSOI2008]最小生成树计数(最小生成树)
总结:此类题需要耐心观察规律,大胆猜想,然后证明猜想,得到有用的性质,然后解答. 简单的说:找隐含性质. 传送门:http://61.187.179.132/JudgeOnline/problem.p ...
- 1016: [JSOI2008]最小生成树计数 - BZOJ
Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...
随机推荐
- [cocos2dx] lua注册回调到c++
思路 像所有语言一样,绑定回调主要是执行的任务执行到特定情形的时候,调用对用回调方法. 这里也一样.核心思路是,当c代码执行到特定特定情形的时候,调用lua的方法 我这里使用的是用lua_stack直 ...
- Cross the GreateWall方案
涉及Client端和Server端 服务端:SS搭建 注意:以Ubuntu环境为例 Step1:添加GPG Public key wget -O- http://shadowsocks.org/deb ...
- swift 开发学习问题
1 UITableViewController 问题: [UITableView dequeueReusableCellWithIdentifier:forIndexPath:], unable to ...
- vector 向量容器用法祥解
vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的. 用法: ...
- yum软件管理器,及yum源配置
说到yum源就必须说到linux系统中特有的依赖关系问题,yum就是为了解决依赖关系而存在的.yum源就相当是一个目录项,当我们使用yum机制安装软件时,若需要安装依赖软件,则yum机制就会根据在yu ...
- Codeforces Round #309 (Div. 2)D
C. Kyoya and Colored Balls time limit per test 2 seconds memory limit per test 256 megabytes input s ...
- oracle排序的几种方法
1.创建数据库表 CREATE TABLE USER_INFO( USERID VARCHAR2(10 BYTE) NOT NULL, USERNAME ...
- Ubuntu16.04 install jdk-8u144-linux-x64.tar.gz
打开终端: Ctrl+Alt+T 下载jdk: wget http://download.oracle.com/otn-pub/java/jdk/8u144-b01/090f390dda5b47b9b ...
- Python自学笔记-面向对象相关(Mr seven)
---恢复内容开始--- http://www.cnblogs.com/wupeiqi/articles/5433893.html 类的成员可以分为三大类:字段.方法和属性. 一.字段 字段包括:普通 ...
- 802.1Q VLAN技术原理
文章出处:http://hi.baidu.com/x278384/item/d56b0edfd4f56a4eddf9be79 在数据通信和宽带接入设备里,只要涉及到二层技术的,就会遇到VLAN.而且, ...