code1002 搭桥

最小生成树

每读入一个城市,把他与之前的所有城市做一次link()

link的内容:

1.如果两个城市直接相连,合并他们的集合(并查集)
2.如果两个城市可以搭桥,添加一条边来连接。如果不可以搭桥,什么也不做。

接着循环所有pa[],如果pa[i]==i,那么这是一个city。这样计算city数量

做kruskal,计算桥的数量和桥的总长度

代码:

#include<iostream>
#include<cstdlib>
#include<algorithm>
#define Size 5005
using namespace std;

int n,m;
int city[Size][2]; int num=0;
int dis=0,num_city=0,num_bridge=0;

int pa[Size];
void init(){
    for(int i=1;i<=n*m;i++){pa[i]=i;}
}
int find(int x){
    if(x!=pa[x])pa[x]=find(pa[x]);
    return pa[x];
}
bool query(int x,int y){
    return find(x)==find(y);
}
void un(int x,int y){
    if(query(x,y))return;
    pa[find(x)]=find(y);
}

struct E{
    int a,b,w;
}edge[100005];
int cnt=0;
int add(int a,int b,int w){
    cnt++;
    edge[cnt].a=a;
    edge[cnt].b=b;
    edge[cnt].w=w;
}

void link(int a,int b){
    int cx=abs(city[a][0]-city[b][0]);
    int cy=abs(city[a][1]-city[b][1]);
    
    if(cx<=1&&cy<=1){un(a,b); return;}
    if(cx>=2&&cy>=2)return;
    
    if(cx>=2)add(a,b,cx-1);
    else add(a,b,cy-1);
}

bool ff(E a,E b){
    return a.w<b.w;
}

void kruskal(){
    sort(edge+1,edge+1+cnt,ff);
    
    for(int i=1;i<=cnt;i++){
        int a=edge[i].a,b=edge[i].b;
        if(!query(a,b)){
            dis+=edge[i].w;
            num_bridge++;
            un(a,b);
        }
    }
}

int main(){
    cin>>n>>m;
    init();
    char cc;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>cc;
            if(cc=='#'){
                num++;
                city[num][0]=i; city[num][1]=j;
                for(int k=1;k<num;k++){
                    link(k,num);
                }
            }
        }
    }
//    cout<<num<<endl;
//    for(int i=1;i<=cnt;i++){
//        cout<<edge[i].a<<' '<<edge[i].b<<' '<<edge[i].w<<endl;
//    }
    for(int i=1;i<=num;i++){
        if(pa[i]==i)num_city++;
    }
    kruskal();
    cout<<num_city<<endl<<num_bridge<<' '<<dis<<endl;
} 
原文地址:https://www.cnblogs.com/FuTaimeng/p/5657104.html