[JSOI2008]最小生成树计数

 

OJ题号:
  BZOJ1016

题目大意:
  给定一个无向带权图,求最小生成树的个数。

思路:
  先跑一遍最小生成树,统计相同权值的边出现的个数。
  易证不同的最小生成树,它们不同的那一部分边的权值实际上是相同的。
  所以我们可以暴力枚举相同权值的边,统计加入这些边总共能有多少种方法。
  根据乘法原理,把每种边的方法数乘起来即可。
  然后就O(2^n)暴力水过这道题。
  实际上用Matrix-Tree可以做到O(n^3)。

  1 */
  2 #include<cstdio>
  3 #include<cctype>
  4 #include<vector>
  5 #include<algorithm>
  6 
  7 inline int getint() {
  8     register char ch;
  9     while(!isdigit(ch=getchar()));
 10     register int x=ch^'0';
 11     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 12     return x;
 13 }
 14 const int mod=31011;
 15 const int V=101;
 16 
 17 struct Edge1 {
 18     int u,v,w;
 19     bool operator < (const Edge1 &another) const {
 20         return w<another.w;
 21     }
 22 };
 23 std::vector<Edge1> e1;
 24 
 25 struct Edge {
 26     int to,w;
 27 };
 28 std::vector<Edge> e[V];
 29 inline void add_edge(const int &u,const int &v,const int &w) {
 30     e[u].push_back((Edge){v,w});
 31 }
 32 
 33 struct DisjointSet {
 34     int anc[V],cnt;
 35     int find(const int &x) const {
 36         return x==anc[x]?x:find(anc[x]);
 37     }
 38     void reset(const int &n) {
 39         cnt=n;
 40         for(register int i=1;i<=n;i++) {
 41             anc[i]=i;
 42         }
 43     }
 44     void Union(const int &x,const int &y) {
 45         anc[find(x)]=find(y);
 46         cnt--;
 47     }
 48     bool isConnected(const int &x,const int &y) const {
 49         return find(x)==find(y);
 50     }
 51     int stat() const {
 52         return cnt;
 53     }
 54 };
 55 DisjointSet s;
 56 
 57 struct Hash {
 58     unsigned l,r;
 59     int v;
 60 };
 61 std::vector<Hash> a;
 62 
 63 inline void kruskal() {
 64     std::sort(e1.begin(),e1.end());
 65     for(register unsigned i=0;i<e1.size();i++) {
 66         if(!i) {
 67             a.push_back((Hash){0,0,0});
 68         } else if(e1[i].w!=e1[i-1].w) {
 69             a.back().r=i-1;
 70             a.push_back((Hash){i,0,0});
 71         }
 72         const int &u=e1[i].u,&v=e1[i].v,&w=e1[i].w;
 73         if(s.isConnected(u,v)) continue;
 74         s.Union(u,v);
 75         add_edge(u,v,w);
 76         add_edge(v,u,w);
 77         a.back().v++;
 78     }
 79     a.back().r=e1.size()-1;
 80 }
 81 
 82 int tmp;
 83 void dfs(const int &in,const unsigned x,const int d) {
 84     if(x>a[in].r) {
 85         if(d==a[in].v) tmp++;
 86         return;
 87     }
 88     const int &u=e1[x].u,&v=e1[x].v;
 89     const int p=s.find(u),q=s.find(v);
 90     if(p!=q) {
 91         s.anc[p]=q;
 92         dfs(in,x+1,d+1);
 93         s.anc[p]=p;
 94         s.anc[q]=q;
 95     }
 96     dfs(in,x+1,d);
 97 }
 98 
 99 int main() {
100     int n=getint();
101     for(register int m=getint();m;m--) {
102         const int u=getint(),v=getint(),w=getint();
103         e1.push_back((Edge1){u,v,w});
104     }
105     s.reset(n);
106     kruskal();
107     if(s.stat()!=1) {
108         puts("0");
109         return 0;
110     }
111     s.reset(n);
112     int ans=1;
113     for(register unsigned i=0;i<a.size();i++) {
114         tmp=0;
115         dfs(i,a[i].l,0);
116         ans=(ans*tmp)%mod;
117         for(register unsigned j=a[i].l;j<=a[i].r;j++) {
118             const int &u=e1[j].u,&v=e1[j].v;
119             if(s.isConnected(u,v)) continue;
120             s.Union(u,v);
121         }
122     }
123     printf("%d\n",ans);
124     return 0;
125 }

 

posted @ 2017-09-22 16:08  skylee03  阅读(181)  评论(0编辑  收藏  举报