zoukankan      html  css  js  c++  java
  • BZOJ1016:[JSOI2008]最小生成树计数(最小生成树,DFS)

    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

    Solution 

    有两条定理:

    1.不同的最小生成树中,每种权值的边出现的个数是确定的。

    2.不同的生成树中,某一种权值的边连接完成后,形成的联通块状态是一样的 。

    也就是说可以对于权值相同的那些边分别处理,爆搜出所有可能的连边情况,然后乘法原理计数即可。

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define N (1009)
     5 #define MOD (31011)
     6 using namespace std;
     7 
     8 struct Edge
     9 {
    10     int x,y,v;
    11     bool operator < (const Edge &a) const{return v<a.v;}
    12 }E[N];
    13 struct Node{int l,r;}a[N];
    14 int n,m,k,fa[N],size[N],cnt,ans=1,sum;
    15 
    16 int Find(int x){return x==fa[x]?x:Find(fa[x]);}
    17 
    18 void Dfs(int l,int r,int d,int v)
    19 {
    20     if (l>r)
    21     {
    22         if (d==size[v]) sum=(sum+1)%MOD;
    23         return;
    24     }
    25     if (r-l+1+d<size[v]) return;
    26     int fx=Find(E[l].x), fy=Find(E[l].y);
    27     if (fx!=fy && d<size[v])
    28     {
    29         fa[fx]=fy;
    30         Dfs(l+1,r,d+1,v);
    31         fa[fx]=fx;
    32     }
    33     Dfs(l+1,r,d,v);
    34 }
    35 
    36 int main()
    37 {
    38     scanf("%d%d",&n,&m);
    39     for (int i=1; i<=m; ++i)
    40         scanf("%d%d%d",&E[i].x,&E[i].y,&E[i].v);
    41     sort(E+1,E+m+1);
    42     for (int i=1; i<=n; ++i) fa[i]=i;
    43     for (int i=1; i<=m; ++i)
    44     {
    45         if (E[i].v!=E[i-1].v) a[++k].l=i, a[k-1].r=i-1;
    46         int fx=Find(E[i].x), fy=Find(E[i].y);
    47         if (fx!=fy) fa[fx]=fy,cnt++,size[k]++;
    48     }
    49     a[k].r=m;
    50     if (cnt!=n-1){puts("0"); return 0;}
    51 
    52     for (int i=1; i<=n; ++i) fa[i]=i;
    53     for (int i=1; i<=k; ++i)
    54     {
    55         if (!size[i]) continue;
    56         sum=0;
    57         Dfs(a[i].l,a[i].r,0,i);
    58         ans=sum*ans%MOD;
    59         for(int j=a[i].l;j<=a[i].r;j++)
    60         {
    61             int fx=Find(E[j].x), fy=Find(E[j].y);
    62             if(fx!=fy) fa[fx]=fy;
    63         }
    64     }
    65     printf("%d
    ",ans);
    66 }
  • 相关阅读:
    MATLAB仿真学习笔记(一)
    SolidWorks学习笔记(一)
    机械制造技术学习笔记(七)
    基于MATLAB的多功能语音处理器
    MATLAB图形界面设计(下)
    36、如何避免僵尸进程?
    37、局部性原理你知道吗?主要有哪两大局部性原理?各自是什么?
    35、 守护进程、僵尸进程和孤儿进程
    32、什么是快表,你知道多少关于快表的知识?
    30、终端退出,终端运行的进程会怎样?31、如何让进程后台运行
  • 原文地址:https://www.cnblogs.com/refun/p/9705392.html
Copyright © 2011-2022 走看看