题目描述 Description
有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。
输入描述 Input Description
在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= r <= 50 and 1 <= c <= 50). 接下来的r 行, 每一行由c 个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。
输出描述 Output Description
在输出的数据中有两行,第一行表示建筑物的数目。第二行输出桥的数目和所有桥的总长度。
一个联通块就是一座城市,两座城市搭桥即是联通块之间连边,注意的是联通块中有n个点,那就得连n条边QAQ
连边的时候方向是不变的,即搭的桥不能转弯,而且方向是可以偏移一行的……
对于联通块中的一个点,将其向正右(x,i),右上(x-1,i),右下(x+1,i),正左(x,i),左上(x-1,i),左下(x+1,i),正上(i,y),上左(i-1,y),上右(i+1,y),正下(i,y),下右(i+1,y),下左(i-1,y)单一方向寻找,如果路径上有另一联通块,就将其连边
所有的边全部建立之后进行最小生成树即可
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=233333;
int map[500][500];
bool use[500][500];
int x_x[9]={0,0,0,1,-1,1,1,-1,-1};
int y_y[9]={0,1,-1,0,0,1,-1,1,-1};
struct doubi{
int x,y;
};
struct faq{
int f,t,d;
}num[maxn];
int n,m;
queue<doubi> q;
void bfs(int i,int j,int cnt){
memset(use,0,sizeof(use));
doubi s;
s.x=i,s.y=j;
map[i][j]=cnt;
q.push(s);
while(!q.empty())
{
doubi u=q.front();
q.pop();
int x=u.x,y=u.y;
for(int i=1;i<=8;i++){
int X=x+x_x[i];
int Y=y+y_y[i];
if(X>=1&&X<=n&&Y>=1&&Y<=m&&!use[X][Y]&&map[X][Y]==-1){
map[X][Y]=cnt;
use[X][Y]=1;
doubi nxt;
nxt.x=X,nxt.y=Y;
q.push(nxt);
}
}
}
}
int fa[maxn];
bool cmp(faq a,faq b){
return a.d<b.d;
}
int find(int a){
if(fa[a]!=a) return fa[a]=find(fa[a]);
else
return a;
}
int main()
{
scanf("%d%d",&n,&m);
char x;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>x;
if(x=='#'){
map[i][j]=-1;
}
}
}
int cnt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(map[i][j]==-1&&!use[i][j]){
bfs(i,j,++cnt);
}
}
}
int tot=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(map[i][j]){
for(int k=j;k<=m;k++){//横右
if(map[i][k]&&map[i][k]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[i][k];
num[tot].d=abs(k-j-1);
}
}
for(int k=j;k<=m;k++){//横右上
if(map[i+1][k]&&map[i+1][k]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[i+1][k];
num[tot].d=abs(k-j-1);
}
}
for(int k=j;k<=m;k++){//横右下
if(map[i-1][k]&&map[i-1][k]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[i-1][k];
num[tot].d=abs(k-j-1);
}
}
for(int k=i;k<=n;k++){//竖下
if(map[k][j]&&map[k][j]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[k][j];
num[tot].d=abs(k-i-1);
}
}
for(int k=i;k<=n;k++){//竖下右
if(map[k][j+1]&&map[k][j+1]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[k][j+1];
num[tot].d=abs(k-i-1);
}
}
for(int k=i;k<=n;k++){//竖下左
if(map[k][j-1]&&map[k][j-1]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[k][j-1];
num[tot].d=abs(k-i-1);
}
}
for(int k=j;k>=1;k--){//横左
if(map[i][k]&&map[i][k]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[i][k];
num[tot].d=abs(k-j-1);
}
}
for(int k=j;k>=1;k--){//横左上
if(map[i+1][k]&&map[i+1][k]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[i+1][k];
num[tot].d=abs(k-j-1);
}
}
for(int k=j;k>=1;k--){//横左下
if(map[i-1][k]&&map[i-1][k]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[i-1][k];
num[tot].d=abs(k-j-1);
}
}
for(int k=i;k>=1;k--){//竖上
if(map[k][j]&&map[k][j]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[k][j];
num[tot].d=abs(k-i-1);
}
}
for(int k=i;k>=1;k--){//竖上右
if(map[k][j+1]&&map[k][j+1]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[k][j+1];
num[tot].d=abs(k-i-1);
}
}
for(int k=i;k>=1;k--){//竖上左
if(map[k][j-1]&&map[k][j-1]!=map[i][j]){
num[++tot].f=map[i][j];
num[tot].t=map[k][j-1];
num[tot].d=abs(k-i-1);
}
}
}
}
}
sort(num+1,num+1+tot,cmp);
long long ans=0;
int count=0;
for(int i=1;i<=cnt;i++){
fa[i]=i;
}
for(int i=1;i<=tot;i++){
int x=find(num[i].f),y=find(num[i].t);
if(x!=y){
fa[x]=y;
ans+=num[i].d;
count++;
}
}
cout<<cnt<<endl<<count<<" "<<ans<<endl;
return 0;
}