BZOJ1016: [JSOI2008]最小生成树计数

题意

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)数据保证不会出现自回边和重边,具有相同权值的边不会超过10条。
1<=n<=100; 1<=m<=1000;

题解

做这道题需要先推出一些结论。
如果把权值相同的边看做一个边组。则所有最小生成树中,每个边组所用的边都是固定的。而且造成的效果相同。所谓效果相同,前若干组边都选好之后,图的连通性是相同的。这些都比较显然,因为所有最小生成树都是n-1条边,边权和都相同,再考虑kruskal的过程即可得到。
也就是说,每组边之间是相互独立的。可以单独计算方案数然后乘法原理。
由于这题保证具有相同权值的边不会超过10条,直接暴力即可,否则求每组边的方案数要用到基尔霍夫矩阵。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=105, maxe=1005, MOD=31011;
struct Edge{
    int x,y,w;
    bool operator < (const Edge &b)const{
        return w<b.w;
    }
} Es[maxe];
struct Group{ int L,R,num; } g[maxe];
int n,m,fa[maxn],G,ans,res;
int getfa(int x){ return fa[x]==x?x:getfa(fa[x]); }
void dfs(int id,int step,int now){
    if(step>g[id].R){
        if(now==g[id].num) res++;
        return;
    }
    dfs(id,step+1,now);
    int fax=getfa(Es[step].x),fay=getfa(Es[step].y);
    if(fax!=fay){
        fa[fax]=fay;
        dfs(id,step+1,now+1);
        fa[fax]=fax; fa[fay]=fay;
    }
}
int main(){
    freopen("bzoj1016.in","r",stdin);
    freopen("bzoj1016.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d%d%d",&Es[i].x,&Es[i].y,&Es[i].w);
    sort(Es+1,Es+1+m);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++){
        if(Es[i].w!=Es[i-1].w) g[G].R=i-1, g[++G].L=i;
        int fax=getfa(Es[i].x),fay=getfa(Es[i].y);
        if(fax!=fay) fa[fax]=fay, g[G].num++, ans++;
    } g[G].R=m;
    if(ans<n-1){ printf("0\n"); return 0; }
    ans=1;
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=G;i++){
        res=0; dfs(i,g[i].L,0);
        ans=ans*res%MOD;
        for(int j=g[i].L;j<=g[i].R;j++){
            int fax=getfa(Es[j].x),fay=getfa(Es[j].y);
            if(fax!=fay) fa[fax]=fay;
        }
    }
    printf("%d\n",ans);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值