luogu4208

Posted gaojunonly1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu4208相关的知识,希望对你有一定的参考价值。

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=0; bool f=0; char ch= ;
    while(!isdigit(ch))    f|=(ch==-); ch=getchar();
    while(isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    return (f)?(-s):(s);

#define R(x) x=read()
inline void write(ll x)

    if(x<0) putchar(-); x=-x;
    if(x<10) putchar(x+0); return;
    write(x/10); putchar((x%10)+0);

#define W(x) write(x),putchar(‘ ‘)
#define Wl(x) write(x),putchar(‘\n‘)
const int N=105,M=1005,Mod=31011;
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+1)
    
        if(cnt==0) return 1;
        return 0;
    
    int ans=dfs(now+1,end,cnt);
    int fx=gl(E[now].u),fy=gl(E[now].v);
    if(fx!=fy)
    
        lian[fx]=fy;
        ans+=dfs(now+1,end,cnt-1);
        lian[fx]=fx;
    
    return ans;

int main()

    int i,j,tot=0;
    R(n); R(m);
    for(i=1;i<=m;i++)
    
        R(E[i].u); R(E[i].v); R(E[i].w);
    sort(E+1,E+m+1,cmpw);
    for(i=1;i<=n;i++) fa[i]=i;
    int ans=1;
    for(i=1;i<=m;)
    
        for(j=1;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-1,tot-now)%Mod;
    
    if(tot==n-1) Wl(ans);
    else puts("0");
    return 0;
View Code

 

 

以上是关于luogu4208的主要内容,如果未能解决你的问题,请参考以下文章

LUOGU P1072

[luogu4556]雨天的尾巴

(luogu题解搬运系列)luogu p2651 添加括号Ⅲ

(luogu题解搬运系列)luogu p1459 三值的排序

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)

[luogu4315]月下“毛景树”