zoukankan      html  css  js  c++  java
  • 1016: [JSOI2008]最小生成树计数

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 7265  Solved: 3003
    [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,0
    00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过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
     
    首先要知道一个最小生成树性质:
      对于一个最小生成树中边权相等的边,如果替换后不影响连通情况,则这就是一个新的最小生成树。
    也就是说,对于一个最小生成树,边权相等的边的数量是固定的,因此我们只需要枚举这些边,再利用乘法原理,得出答案
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 
      7 const int mod=31011;
      8 
      9 struct Edge
     10 {
     11     int u,v,w;
     12 }E[2000];
     13 
     14 struct Line
     15 {
     16     int l,r,v;
     17 }L[2000];
     18 int node;
     19 
     20 int n,m,tot,sum,ans=1;
     21 int F[10000];
     22 
     23 bool cmp(Edge A,Edge B)
     24 {
     25     return A.w<B.w;
     26 }
     27 
     28 int find(int x)
     29 {
     30     while(F[x]!=x) x=F[x];
     31     return x;
     32 }
     33 
     34 void dfs(int x,int now,int k)
     35 {
     36     if(now==L[x].r+1)
     37     {
     38         if(k==L[x].v) sum++;
     39         return;
     40     }
     41     int u=find(E[now].u);
     42     int v=find(E[now].v);
     43     if(u!=v)
     44     {
     45         F[u]=v;
     46         dfs(x,now+1,k+1);
     47         F[u]=u;F[v]=v;
     48     }
     49     dfs(x,now+1,k);
     50 }
     51 
     52 int main()
     53 {
     54     scanf("%d %d",&n,&m);
     55     for(int i=1;i<=n;i++) F[i]=i;
     56     for(int i=1;i<=m;i++)
     57     {
     58         int u,v,w;
     59         scanf("%d %d %d",&u,&v,&w);
     60         E[i]=(Edge){u,v,w};
     61     }
     62     sort(E+1,E+m+1,cmp);
     63     for(int i=1;i<=m;i++)
     64     {
     65         if(E[i].w!=E[i-1].w)
     66         {
     67             L[node].r=i-1;
     68             L[++node].l=i;
     69         }
     70         int u=find(E[i].u);
     71         int v=find(E[i].v);
     72         if(u!=v)
     73         {
     74             F[u]=v;
     75             L[node].v++;
     76             tot++;
     77         }
     78     }
     79     L[node].r=m;
     80     if(tot!=n-1)
     81     {
     82         printf("0");
     83         return 0;
     84     }
     85     for(int i=1;i<=n;i++) F[i]=i;
     86     for(int i=1;i<=node;i++)
     87     {
     88         sum=0;
     89         dfs(i,L[i].l,0);
     90         ans=(ans*sum)%mod;
     91         for(int j=L[i].l;j<=L[i].r;j++)
     92         {
     93             int u=find(E[j].u);
     94             int v=find(E[j].v);
     95             if(u!=v) F[u]=v;
     96         }
     97     }
     98     printf("%d
    ",ans);
     99     return 0;
    100 }
  • 相关阅读:
    NAVICAT 拒绝链接的问题
    .net垃圾回收-原理浅析
    C#中标准Dispose模式的实现
    Windbg调试托管代码
    C#泛型基础
    .Net垃圾回收和大对象处理
    C++ 小知识点
    C++之虚函数表
    C++之指针与引用,函数和数组
    C++之const关键字
  • 原文地址:https://www.cnblogs.com/InWILL/p/9451722.html
Copyright © 2011-2022 走看看