• BZOJ 1016 [JSOI2008]最小生成树计数


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

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 3529  Solved: 1404
    [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,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

    Output

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

    Sample Input

    4 6
    1 2 1
    1 3 1
    1 4 1
    2 3 2
    2 4 1
    3 4 1

    Sample Output

    8

    HINT

     

    Source

    题解:同一个图的最小生成树,满足:

    1)同一种权值的边的个数相等

    2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性相等

    这样,先做一次Kruscal求出每种权值的边的条数,再按照权值从小到大,对每种边进行 DFS, 求出这种权值的边有几种选法。

    最后根据乘法原理将各种边的选法数乘起来就可以了。

    特别注意:在DFS中为了在向下DFS之后消除决策影响,恢复f[]数组之前的状态,在DFS中调用的Find()函数不能路径压缩。 

    代码们:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cstring>
     7 #define PAU putchar(' ')
     8 #define ENT putchar('
    ')
     9 using namespace std;
    10 const int maxn=100+10,maxm=1000+10,inf=-1u>>1,mod=31011;
    11 struct edge{int x,y,w;}e[maxm];struct data{int L,R,num;}a[maxm];
    12 int n,m,cnt,tot,ans=1,sum,fa[maxn];
    13 bool cmp(const edge&a,const edge&b){return a.w<b.w;}
    14 int find(int x){return x==fa[x]?x:find(fa[x]);}
    15 int findset(int x){return x==fa[x]?x:fa[x]=findset(fa[x]);}
    16 void dfs(int x,int pos,int k){
    17     if(pos>a[x].R){if(k==a[x].num)sum++;return;}
    18     int f1=find(e[pos].x),f2=find(e[pos].y);
    19     if(f1!=f2)fa[f1]=f2,dfs(x,-~pos,-~k),fa[f1]=f1;
    20     dfs(x,-~pos,k);return;
    21 }
    22 inline int read(){
    23     int x=0,sig=1;char ch=getchar();
    24     while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();}
    25     while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
    26     return x*=sig;
    27 }
    28 inline void write(int x){
    29     if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
    30     int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;
    31     for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
    32 }
    33 void init(){
    34     n=read();m=read();
    35     for(int i=1;i<=n;i++) fa[i]=i;
    36     for(int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].w=read();
    37     sort(e+1,e+m+1,cmp);
    38     for(int i=1;i<=m;i++){
    39         if(e[i].w!=e[i-1].w){a[++cnt].L=i;a[cnt-1].R=i-1;}
    40         int f1=findset(e[i].x),f2=findset(e[i].y);
    41         if(f1!=f2){fa[f1]=f2;a[cnt].num++;tot++;}
    42     }
    43     return;
    44 }
    45 void work(){
    46     a[cnt].R=m;
    47     if(tot<n-1){write(0);return;}
    48     for(int i=1;i<=n;i++) fa[i]=i;
    49     for(int i=1;i<=cnt;i++){
    50         sum=0;dfs(i,a[i].L,0);
    51         ans=(ans*sum)%mod;
    52         for(int j=a[i].L;j<=a[i].R;j++){
    53             int f1=find(e[j].x),f2=find(e[j].y);
    54             if(f1!=f2)fa[f1]=f2;
    55         }
    56     }write(ans);
    57     return;
    58 }
    59 void print(){
    60     return;
    61 }
    62 int main(){init();work();print();return 0;}
  • 相关阅读:
    跳出iframe
    leetcode 225. Implement Stack using Queues
    leetcode 206. Reverse Linked List
    leetcode 205. Isomorphic Strings
    leetcode 203. Remove Linked List Elements
    leetcode 198. House Robber
    leetcode 190. Reverse Bits
    leetcode leetcode 783. Minimum Distance Between BST Nodes
    leetcode 202. Happy Number
    leetcode 389. Find the Difference
  • 原文地址:https://www.cnblogs.com/chxer/p/4648956.html
Copyright © 2020-2023  润新知