P4208 [JSOI2008]最小生成树计数

题目描述

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。

输入格式

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。

接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。

数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

输出格式

输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

输入输出样例

输入 #1复制

4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
输出 #1复制

8

说明/提示

说明 1<=n<=100; 1<=m<=1000;1<=ci<=1e9

sol:相同权值的最小生成树有一个很玄学的特点就是相同边权的边的数量时固定的而且作用也是相同的,然后相同的边的方案数可以爆搜出来,只要注意一点就是搜方案数时的并查集不能路径压缩,否则回溯的时候回挂掉

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
ll s=; bool f=; char ch=' ';
while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();}
while(isdigit(ch)) {s=(s<<)+(s<<)+(ch^); ch=getchar();}
return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
if(x<) {putchar('-'); x=-x;}
if(x<) {putchar(x+''); return;}
write(x/); putchar((x%)+'');
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=,M=,Mod=;
int n,m,fa[N],lian[N];
struct Edge
{
int u,v,w;
}E[M];
inline bool cmpw(Edge p,Edge q) {return p.w<q.w;}
inline int gf(int x){return (fa[x]==x)?x:fa[x]=gf(fa[x]);}
inline int gl(int x){return (lian[x]==x)?x:gl(lian[x]);}
inline int dfs(int now,int end,int cnt)
{
if(now==end+)
{
if(cnt==) return ;
return ;
}
int ans=dfs(now+,end,cnt);
int fx=gl(E[now].u),fy=gl(E[now].v);
if(fx!=fy)
{
lian[fx]=fy;
ans+=dfs(now+,end,cnt-);
lian[fx]=fx;
}
return ans;
}
int main()
{
int i,j,tot=;
R(n); R(m);
for(i=;i<=m;i++)
{
R(E[i].u); R(E[i].v); R(E[i].w);
}sort(E+,E+m+,cmpw);
for(i=;i<=n;i++) fa[i]=i;
int ans=;
for(i=;i<=m;)
{
for(j=;j<=n;j++) lian[j]=j;
int oo=i,now=tot;
while(i<=m&&E[i].w==E[oo].w)
{
E[i].u=gf(E[i].u); E[i].v=gf(E[i].v); i++;
}
for(j=oo;j<i;j++)
{
int fx=gf(E[j].u),fy=gf(E[j].v);
if(fx!=fy)
{
tot++; fa[fx]=fy;
}
}
ans=1LL*ans*dfs(oo,i-,tot-now)%Mod;
}
if(tot==n-) Wl(ans);
else puts("");
return ;
}

luogu4208的更多相关文章

  1. bzoj1016/luogu4208 最小生成树计数 (kruskal+暴搜)

    由于有相同权值的边不超过10条的限制,所以可以暴搜 先做一遍kruskal,记录下来每个权值的边使用的数量(可以离散化一下) 可以证明,对于每个权值,所有的最小生成树中选择的数量是一样的.而且它们连成 ...

随机推荐

  1. apply,call和bind的使用及区别

    1.用途 1)apply,call和bind都是 用来改变this的指向 2)apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行 2.this指向问题 thi ...

  2. #448 div2 a Pizza Separation

    A. Pizza Separation time limit per test1 second memory limit per test256 megabytes inputstandard inp ...

  3. 使用Docker发布Asp.Net Core程序到Linux

    CentOS安装Docker 按照docker官方文档来,如果有之前安装过旧版,先卸载旧版,没有的话,可跳过. sudo yum remove docker \ docker-client \ doc ...

  4. 在ubuntu 16.04 的vm中添加新网卡,同一网段不同ip

    在ubuntu 16.04 的vm中添加新网卡,同一网段不同ip 来源 https://blog.51cto.com/744478/2083672 在ubuntu 16.04 的vm中新加了一块网卡, ...

  5. js数组转对象

    var obj = {}; var arr = [1,2,3,4,5]; for (var x in arr){ obj[x] = x; } 2.ES6的Object.assign: Object.a ...

  6. 在iframe内页触发顶层页面body的blur事件

    //在iframe内页触发顶层页面body的blur事件. if (window != top) { $(document.body).click(function () { $(top.docume ...

  7. Java并发 行级锁/字段锁/表级锁 乐观锁/悲观锁 共享锁/排他锁 死锁

    原文地址:https://my.oschina.net/oosc/blog/1620279 前言 锁是防止在两个事务操作同一个数据源(表或行)时交互破坏数据的一种机制. 数据库采用封锁技术保证并发操作 ...

  8. 在SAP除了使用Cordova生产移动应用外,还有这种方式

    本文和Jerry过去的文章不太一样,算不上Jerry的知识分享,只是记录一下Jerry用React-Native把应用安装到Android手机上遇到的一些问题,方便以后查看. Jerry的同事Leo用 ...

  9. 关于MUI页面之间传值以及刷新的问题

    一.页面刷新问题 1.父页面A跳转到子页面B,B页面修改数据后再跳回A页面,刷新A页面数据 (1).父页面A代码 window.addEventListener("pageflowrefre ...

  10. base64码通过http传输 +号变 空格 以及 图片编码后字符串较长导致POST提交失败 问题解决

    场景:图片上传OSS存储,接口拿字符串去接前端传的base64码,服务器打印入参传的值,发现和前端打印的值有所区别,服务器中打印的值所有+号全部变成空格. 解决办法: Java中使用:url = ur ...