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\n", 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

 

posted @ 2015-02-20 16:02  idy002  阅读(...)  评论(... 编辑 收藏