zoukankan      html  css  js  c++  java
  • bzoj 1016 最小生成树计数

    给定一个简单无向有权图,求其最小生成树的个数。

    在我们用Kruskal计算最小生成树时,由于相同权值的边选择的顺序是随机的,所以我们最小生成树就也许有很多。

    对于同一权值的边,我们不论用什么顺序“扫过”,最终的得到的无向森林的连通性一定是一样的,即对后面的边是否加入的影响也是一样的,所以可以根据这一点将最小生成树分阶段统计,所有权值相同的边为一阶段,每个阶段都有一个方案数,最终的答案便是方案数的乘积。

    对于某一阶段的一个选边的合法方案是什么呢?就是这些边加入到图中,使图的连通性和“按任意顺序扫一遍,能加就加”后的连通性一样。

    至于怎么计算,先扫一遍,将减少的连通块的数量记下来,然后撤销操作,枚举边集(2^10),判断该边集加入后减少的联通快是否一样,一样就合法。

    也可以将到达这一阶段时,图中的联通快缩成一个点,然后计算当前阶段的边和缩了点后的图的联通快,每个连通块计算生成树个数,它们的乘积就是本阶段的方案数

    我用的是第二种方法,有点难写

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <map>
      4 #include <vector>
      5 #include <algorithm>
      6 #define abs(a) ((a)<0?-(a):(a))
      7 #define M 31011
      8 #define maxn 110
      9 using namespace std;
     10 
     11 struct Edge {
     12     int u, v, w;
     13     Edge( int u, int v, int w ) : u(u), v(v), w(w) {}
     14     bool operator<( const Edge & b ) const {
     15         return w<b.w;
     16     }
     17 };
     18 
     19 typedef int Matrix[maxn][maxn];
     20 
     21 int n, m;
     22 vector<Edge> edge;
     23 
     24 int fa[maxn];
     25 
     26 void init() {
     27     for( int i=1; i<=n; i++ ) fa[i]=i;
     28 }
     29 int find( int a ) {
     30     return fa[a]==a ? a : fa[a]=find(fa[a]);
     31 }
     32 void unon( int a, int b ) {
     33     a = find(a);
     34     b = find(b);
     35     fa[a] = b;
     36 }
     37 
     38 int det( Matrix a, int n ) {
     39     for( int i=0; i<n; i++ ) {
     40         int r = i;
     41         for( int j=i+1; j<n; j++ )
     42             if( abs(a[j][i])>abs(a[r][i]) ) r=j;
     43         if( r!=i )
     44             for( int k=i; k<n; k++ )
     45                 swap( a[i][k], a[r][k] );
     46         if( a[i][i]==0 ) return 0;
     47         for( int j=i+1; j<n; j++ ) {
     48             while( a[j][i] ) {
     49                 int d = a[i][i] / a[j][i];
     50                 for( int k=i; k<n; k++ ) {
     51                     a[i][k] = (a[i][k]-a[j][k]*d%M)%M;
     52                     swap( a[i][k], a[j][k] );
     53                 }
     54             }
     55         }
     56     }
     57     int rt = 1;
     58     for( int i=0; i<n; i++ )
     59         rt = (rt*a[i][i])%M;
     60     return abs(rt);
     61 }
     62 
     63 int subfa[30], cnt;
     64 Matrix a;
     65 int sfind( int a ) {
     66     return a==subfa[a] ? a : subfa[a]=sfind(subfa[a]);
     67 }
     68 void sunon( int a, int b ) {
     69     a = sfind(a);
     70     b = sfind(b);
     71     if( b<a ) subfa[a] = b;
     72     else subfa[b] = a;
     73 }
     74 int pm( map<int,int> &mp, int i ) { return mp[i]; }
     75 int calc( const vector<Edge> & e ) {
     76     vector<int> cc[30];
     77     map<int,int> mp;
     78     cnt = 0;
     79     for( int i=0; i<e.size(); i++ ) {
     80         int u = e[i].u, v = e[i].v;
     81         if( !mp.count(find(u)) ) mp[find(u)]=cnt++;
     82         if( !mp.count(find(v)) ) mp[find(v)]=cnt++;
     83     }
     84     for( int i=0; i<mp.size(); i++ ) subfa[i] = i;
     85     for( int i=0; i<e.size(); i++ ) {
     86         int u = e[i].u, v = e[i].v;
     87         sunon( mp[find(u)], mp[find(v)] );
     88     }
     89     int rt = 1;
     90     for( int i=0; i<cnt; i++ ) 
     91         cc[sfind(i)].push_back(i);
     92     for( int c=0; cc[c].size(); c++ ) {
     93         if( cc[c].size()==1 ) continue;
     94         map<int,int> np;
     95         for( int t=0; t<cc[c].size(); t++ ) 
     96             np[cc[c][t]] = t;
     97         memset( a, 0, sizeof(a) );
     98         for( int i=0; i<e.size(); i++ ) {
     99             int u = np[mp[find(e[i].u)]];
    100             int v = np[mp[find(e[i].v)]];
    101             a[u][u]++;
    102             a[v][v]++;
    103             a[u][v]--;
    104             a[v][u]--;
    105         }
    106         rt = (rt*det(a,cc[c].size()-1))%M;
    107     }
    108     return rt;
    109 }
    110 void work() {
    111     sort( edge.begin(), edge.end() );
    112     init();
    113     vector<Edge> e;
    114     int ans = 1;
    115     for( int i=0; i<edge.size(); ) {
    116         do 
    117             e.push_back( edge[i++] );
    118         while( i<edge.size() && edge[i].w==edge[i-1].w );
    119         ans = (ans*calc(e))%M;
    120         while( !e.empty() ) {
    121             unon( e.back().u, e.back().v );
    122             e.pop_back();
    123         }
    124     }
    125     for( int i=2; i<=n; i++ )
    126         if( find(i)!=find(i-1) ) {
    127             ans=0;
    128             break;
    129         }
    130     printf( "%d
    ", ans );
    131 }
    132 
    133 int main() {
    134     scanf( "%d%d", &n, &m );
    135     for( int i=0,u,v,w; i<m; i++ ) {
    136         scanf( "%d%d%d", &u, &v, &w );
    137         edge.push_back( Edge(u,v,w) );
    138     }
    139     work();
    140 }
    View Code
  • 相关阅读:
    决策树【机器学习】
    ACM数论【乘法逆元】
    朴素贝叶斯法【机器学习】
    STL中的一些算法的整理【总结-STL整理】
    感知机【机器学习】
    K近邻法【机器学习】
    【hiho一下】41 斐波那契数列【矩阵快速幂】
    floyd算法【图论
    dijkstra算法【图论
    SPFA算法【图论
  • 原文地址:https://www.cnblogs.com/idy002/p/4296558.html
Copyright © 2011-2022 走看看