一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或Prim(普里姆)算法求出。
生成树是否存在 等价于 图是否连通
题目分析:给图,求最小生成树,Kruskal 和 Prim都试试
Kruskal AC_CODE
const int maxn = 108 ;
const int inf = 1<<30 ;
int n , m ;
struct edge{
int a , b , cost ;
bool friend operator<(const edge &A , const edge &B){
return A.cost < B.cost ;
}
}e[maxn];
int fat[maxn] ;
void init(){
for(int i = 0;i < maxn;i++){
fat[i] = i ;
}
}
int get_Fat(int x){
if(x == fat[x]) return x ;
else return fat[x] = get_Fat(fat[x]) ;
}
void Merg(int u , int v){
int fu = get_Fat(u) ;
int fv = get_Fat(v) ;
if(fu != fv){
fat[fu] = fv ;
}
}
bool same(int u , int v){
int fu = get_Fat(u) ;
int fv = get_Fat(v) ;
if(fu == fv) return true ;
else return false ;
}
int main(){
int i , j , k ;
//freopen("in.txt" , "r" , stdin) ;
while(scanf("%d%d",&n, &m) != EOF){
if(n == 0) break ;
for(i = 0;i < n;i++){
scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].cost) ;
}
sort(e , e + n) ;
int ans = 0 ;
init() ;
set<int> node ;
for(i = 0;i < n;i++){
int a = e[i].a ;
int b = e[i].b ;
if(!same(a , b)){
Merg(a , b) ;
ans += e[i].cost ;
node.insert(a) ;
node.insert(b) ;
}
}
if(node.size() == m) printf("%d\n",ans) ;
else puts("?") ;
}
return 0 ;
}
JD 1017:还是畅通工程
题目分析:与1024一样啦,没什么区别,求最小生成树
Kruskal AC_CODE
const int maxn = 108 ;
const int inf = 1<<30 ;
int n , m ;
struct edge{
int a , b , cost ;
bool friend operator<(const edge &A , const edge &B){
return A.cost < B.cost ;
}
}e[maxn*maxn/2];
int fat[maxn] ;
void init(){
for(int i = 0;i < maxn;i++){
fat[i] = i ;
}
}
int get_Fat(int x){
if(x == fat[x]) return x ;
else return fat[x] = get_Fat(fat[x]) ;
}
void Merg(int u , int v){
int fu = get_Fat(u) ;
int fv = get_Fat(v) ;
if(fu != fv){
fat[fu] = fv ;
}
}
bool same(int u , int v){
int fu = get_Fat(u) ;
int fv = get_Fat(v) ;
if(fu == fv) return true ;
else return false ;
}
int main(){
int i , j , k ;
//freopen("in.txt" , "r" , stdin) ;
while(scanf("%d",&n) != EOF){
if(n == 0) break ;
int m = n*(n-1)/2 ;
for(i = 0;i < m;i++){
scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].cost) ;
}
sort(e , e + m) ;
int ans = 0 ;
init() ;
for(i = 0;i < m;i++){
int a = e[i].a ;
int b = e[i].b ;
if(!same(a , b)){
Merg(a , b) ;
ans += e[i].cost ;
}
}
printf("%d\n",ans) ;
}
return 0 ;
}
JD 1012:畅通工程
题目分析:就是并查集的应用啦,判断有几个等价类
AC_CODE
const int maxn = 1008 ;
int fat[maxn] ;
int n , m ;
void init(){
for(int i = 0;i < maxn;i++)
fat[i] = i ;
}
int GetFat(int x){
if(x == fat[x]) return x ;
else fat[x] = GetFat(fat[x]) ;
}
void Merg(int u , int v){
int fu = GetFat(u) ;
int fv = GetFat(v) ;
if(fu != fv){
fat[fu] = fv ;
}
}
int main(){
//freopen("in.txt","r",stdin) ;
int i , j , k , u , v ;
while(cin >> n){
if(n == 0) break ;
cin >> m ;
init() ;
for(i = 0;i < m;i++){
scanf("%d%d",&u,&v) ;
Merg(u , v) ;
}
set<int> s ;
for(i = 1;i <= n;i++){
s.insert(GetFat(i)) ;
}
printf("%d\n",s.size() - 1) ;
}
}
JD 1028:继续畅通工程
题目分析:最小生成树,用Kruskal
Kruskal AC_CODE
const int maxn = 108 ;
const int inf = 1<<30 ;
int n , m ;
struct edge{
int a , b , cost , flag;
bool friend operator<(const edge &A , const edge &B){
if(A.flag == B.flag) return A.cost < B.cost ;
return A.flag > B.flag ;
}
}e[maxn*maxn/2];
int fat[maxn] ;
void init(){
for(int i = 0;i < maxn;i++){
fat[i] = i ;
}
}
int get_Fat(int x){
if(x == fat[x]) return x ;
else return fat[x] = get_Fat(fat[x]) ;
}
void Merg(int u , int v){
int fu = get_Fat(u) ;
int fv = get_Fat(v) ;
if(fu != fv){
fat[fu] = fv ;
}
}
bool same(int u , int v){
int fu = get_Fat(u) ;
int fv = get_Fat(v) ;
if(fu == fv) return true ;
else return false ;
}
int main(){
int i , j , k ;
//freopen("in.txt" , "r" , stdin) ;
while(scanf("%d",&n) != EOF){
if(n == 0) break ;
int m = n*(n-1)/2 ;
for(i = 0;i < m;i++){
scanf("%d%d%d%d",&e[i].a,&e[i].b,&e[i].cost,&e[i].flag) ;
}
sort(e , e + m) ;
int ans = 0 ;
init() ;
for(i = 0;i < m;i++){
int a = e[i].a ;
int b = e[i].b ;
if(!same(a , b)){
Merg(a , b) ;
ans += e[i].flag ? 0 : e[i].cost ;
}
}
printf("%d\n",ans) ;
}
return 0 ;
}
题目分析:就是求最小生成树
KruskalAC_CODE
typedef long long LL ;
const int inf = 1<<30 ;
const int maxn = 1008 ;
int n , m ;
int fat[maxn] ;
struct Node{
int u , v , d ;
Node(){}
Node(int a , int b , int c):u(a),v(b),d(c){}
bool friend operator<(const Node &A , const Node &B){
return A.d < B.d ;
}
}edge[maxn*10];
void init(){
for(int i = 1;i <= n;i++)
fat[i] = i ;
}
int GetFat(int x){
if(x == fat[x]) return x ;
else return fat[x] = GetFat(fat[x]) ;
}
bool Same(int u ,int v){
int fu = GetFat(u) ;
int fv = GetFat(v) ;
if(fu == fv) return true ;
else return false ;
}
void Merge(int u ,int v){
int fu = GetFat(u) ;
int fv = GetFat(v) ;
if(fu != fv){
fat[fu] = fv ;
}
}
int main(){
int i , j , k , u , v , d;
//freopen("in.txt","r",stdin) ;
while(scanf("%d%d",&n,&m) != EOF){
for(i = 0;i < m;i++){
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].d) ;
}
sort(edge , edge + m) ;
int ans = 0 ;
Node e ;
init() ;
int cnt = 0 ;
for(i = 0;i < m;i++){
e = edge[i] ;
if(!Same(e.u , e.v)){
ans += e.d ;
Merge(e.u , e.v) ;
cnt++ ;
}
}
if(cnt < n - 1) puts("no") ;
else printf("%d\n",ans) ;
}
}
JD 1545:奇怪的连通图
题目分析:这里不是求最小生成树,只要求1与n连通,且使得边长的最大值最小。可利用Kruskal算法思想,1到n连通即可,无须构成最小生成树。
AC_CODE
const int maxn = 10008 ;
const int maxm = 100008 ;
int fat[maxn] ;
int n , m ;
struct edge{
int u , v , d ;
friend bool operator<(const edge &A , const edge &B){
return A.d < B.d ;
}
}e[maxm];
void init(){
int i ;
for(i = 1;i <= n;i++)
fat[i] = i ;
}
int getFat(int x){
if(x == fat[x]) return x ;
else return fat[x] = getFat(fat[x]) ;
}
bool same(int u , int v){
int fu = getFat(u) ;
int fv = getFat(v) ;
return fu == fv ;
}
void Merg(int u , int v){
int fu = getFat(u) ;
int fv = getFat(v) ;
if(fu != fv){
fat[fu] = fv ;
}
}
int main(){
int i , j , k ;
//freopen("in.txt","r",stdin) ;
while(scanf("%d%d",&n,&m) != EOF){
for(i = 0;i < m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].d) ;
sort(e , e + m) ;
init() ;
for(i = 0;i < m;i++){
if(!same(1 , n)){
Merg(e[i].u , e[i].v) ;
k = e[i].d ;
}
else break ;
}
if(same(1 , n)) printf("%d\n",k) ;
else puts("-1") ;
}
return 0 ;
}
题目分析:与1545类似,只不过这里要构成最小生成树。还有,输入时结点的编号用字符串表示的,要hash成整数。其他都一样了。。。
Kruskal AC_CODE
const int maxn = 108 ;
const int maxm = 10008 ;
int fat[maxn] ;
int n , m ;
map< string , int > mp ;
struct edge{
int u , v , d ;
edge(){}
edge(int a , int b , int c):u(a),v(b),d(c){}
friend bool operator<(const edge &A , const edge &B){
return A.d < B.d ;
}
}e[maxm];
void init(){
int i ;
for(i = 1;i <= n;i++)
fat[i] = i ;
}
int getFat(int x){
if(x == fat[x]) return x ;
else return fat[x] = getFat(fat[x]) ;
}
bool same(int u , int v){
int fu = getFat(u) ;
int fv = getFat(v) ;
return fu == fv ;
}
void Merg(int u , int v){
int fu = getFat(u) ;
int fv = getFat(v) ;
if(fu != fv){
fat[fu] = fv ;
}
}
int main(){
int i , j , k , a , b , c ;
//freopen("in.txt","r",stdin) ;
string s ;
while(scanf("%d%d",&n,&m) != EOF){
mp.clear() ;
k = 1 ;
for(i = 0;i < m;i++){
cin >> s ;
if(mp.find(s) == mp.end())
mp[s] = k++ ;
a = mp[s] ;
cin >> s ;
if(mp.find(s) == mp.end())
mp[s] = k++ ;
b = mp[s] ;
scanf("%d",&c) ;
e[i] = edge(a , b , c) ;
}
sort(e , e + m) ;
init() ;
int t = 0 ;
for(i = 0;i < m;i++){
if(!same(e[i].u , e[i].v)){
Merg(e[i].u , e[i].v) ;
k = e[i].d ;
t++ ;
}
}
if(t == n - 1) printf("%d\n",k) ;
else puts("My God") ;
}
return 0 ;
}