BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索
Posted yxysuanfa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索相关的知识,希望对你有一定的参考价值。
题目大意:给出一些边,求出一共能形成多少个最小生成树。
思路:最小生成树有非常多定理啊,我也不是非常明确。这里仅仅简单讲讲做法。关于定各种定理请看这里: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; }
以上是关于BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ-1016: [JSOI2008]最小生成树计数 (kruscal+搜索)
BZOJ1016:[JSOI2008]最小生成树计数——题解