题目大意:给出一些边,求出一共能形成多少个最小生成树。
思路:最小生成树有很多定理啊,我也不是很明白,这里只简单讲讲做法,关于定各种定理请看这里:http://blog.csdn.net/wyfcyx_forever/article/details/40182739
我们先做一次最小生成树,然后记录每一种长度的边有多少在最小生成树中,然后从小到大搜索,看每一种边权有多少种放法,然后所有的都算出来累乘就是最终的结果。
CODE:
#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 2010
#define MO 31011
using namespace std;
map<int,int> G;
struct Complex{
int x,y,len;
bool operator <(const Complex &a)const {
return len < a.len;
}
void Read() {
scanf("%d%d%d",&x,&y,&len);
}
}edge[MAX];
int points,edges;
int ones[MAX];
int father[MAX];
int ans = 1;
void Pretreatment()
{
for(int i = 1;i <= 1025; ++i)
ones[i] = ones[i >> 1] + (i&1);
}
int Find(int x)
{
if(!father[x] || father[x] == x) return father[x] = x;
return father[x] = Find(father[x]);
}
bool Kruskal()
{
int cnt = 0;
for(int i = 1;i <= edges; ++i) {
int fx = Find(edge[i].x);
int fy = Find(edge[i].y);
if(fx != fy) {
father[fy] = fx;
G[edge[i].len]++;
cnt++;
}
}
if(cnt < points - 1) return false;
return true;
}
void DFS(int pos)
{
if(pos > edges) return ;
int st = pos,ed = pos,re = 0;
int cnt = G[edge[st].len];
if(!cnt) {
DFS(ed + 1);
return ;
}
while(edge[ed + 1].len == edge[st].len) ++ed;
for(int i = 0;i < (1 << (ed - st + 1)); ++i)
if(ones[i] == cnt) {
memset(father,0,sizeof(father));
int temp = i;
for(int j = st; temp; temp >>= 1,++j)
if(temp&1) {
int fx = Find(edge[j].x);
int fy = Find(edge[j].y);
if(fx == fy) break;
father[fy] = fx;
}
if(!temp) ++re;
}
ans = (ans * re) % MO;
memset(father,0,sizeof(father));
for(int i = st; i <= ed; ++i) {
int fx = Find(edge[i].x);
int fy = Find(edge[i].y);
if(fx == fy) continue;
father[fy] = fx;
}
for(int i = ed + 1;i <= edges; ++i)
edge[i].x = Find(edge[i].x),edge[i].y = Find(edge[i].y);
DFS(ed + 1);
}
int main()
{
Pretreatment();
cin >> points >> edges;
for(int i = 1;i <= edges; ++i)
edge[i].Read();
sort(edge + 1,edge + edges + 1);
memset(father,0,sizeof(father));
if(!Kruskal()) {
cout << 0 << endl;
return 0;
}
DFS(1);
cout << ans << endl;
return 0;
}