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

Description

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

solution

正解:kruskal+枚举
我们需要明白:对于所有的最小生成树满足:1.相同边权的边数相同。2.相同边权的边合并的点集也是一定的.
两个结论可以一起证明:边数显然不可能增加,不然在做第一次kruskal的时候肯定会被加入,如果边数还可以减少,那么有一些点肯定还没有被合并,那么合并可以使得边数+1.
所以我们枚举边权,因为相同边权的边不超过10,所以对每一种边权枚举,方案相乘即可

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=10005,mod=31011;
int fa[N],n,m,t=0;
struct node{
    int x,y,z;
    bool operator <(const node &pr)const{return z<pr.z;}
}e[N];
inline int find(int x){return fa[x]==x?x:find(fa[x]);}
int l[N],r[N],v[N];
bool priwork(){
    int x,y,cnt=0;
    for(int i=1;i<=m;i++){
        if(e[i].z!=e[i-1].z)t++,l[t]=i;
        r[t]=i;
        x=e[i].x;y=e[i].y;
        if(find(x)==find(y))continue;
        fa[find(y)]=find(x);
        cnt++;v[t]++;
    }
    if(cnt!=n-1)return false;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(find(i)!=find(j))return false;
    return true;
}
int cnt=0;
inline void dfs(int i,int x,int sum){
    if(x>r[i]){if(sum==v[i])cnt++;return ;}
    dfs(i,x+1,sum);
    int a=find(e[x].x),b=find(e[x].y);
    if(a!=b){
        fa[b]=a;
        dfs(i,x+1,sum+1);
        fa[b]=b;fa[a]=a;
    }
}
void work()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)cin>>e[i].x>>e[i].y>>e[i].z;
   for(int i=1;i<=n;i++)fa[i]=i;
    sort(e+1,e+m+1);
    if(!priwork()){puts("0");return ;}
    int ans=1,x,y;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=t;i++){
        cnt=0;
        dfs(i,l[i],0);
        ans*=cnt;if(ans>=mod)ans%=mod;
        for(int j=l[i];j<=r[i];j++){
            x=e[j].x;y=e[j].y;
            if(find(x)==find(y))continue;
            fa[find(y)]=find(x);
        }
    }
    cout<<ans<<endl;
}

int main()
{
    work();
    return 0;
}
posted @ 2017-12-14 21:41  PIPIBoss  阅读(...)  评论(... 编辑 收藏