/* 先来个灌水法 然后建图跑最小生成树 注意观察题目中的规则 a[1][i]!=a[1][j]&&abs(a[2][i]-a[2][j])<=1 建图的时候可以每一个建筑物都看成一个点 然后计算需要几个桥 同一个城市的不用桥 */ #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; int n,m,tot,g[1001][1001],a[3][1001],minn[10001],f[10001],sum,bb; char s[101][101]; int xx[9]={0,0,0,1,1,1,-1,-1,-1};//枚举8个方向 int yy[9]={0,1,-1,-1,0,1,-1,0,1}; void Dfs(int x,int y) { s[x][y]=tot+48; int i,j,ox,oy; for(i=1;i<=8;i++)//枚举8个方向 { ox=x+xx[i];oy=y+yy[i]; if(ox>0&&ox<=n&&oy>0&&oy<=m&&s[ox][oy]=='#') Dfs(ox,oy); } } int main() { cin>>n>>m; int i,j,k,l; for(i=1;i<=n;i++) for(j=1;j<=m;j++) cin>>s[i][j]; for(i=1;i<=n;i++) for(j=1;j<=m;j++) if(s[i][j]=='#')//统计城市个数 { tot++; Dfs(i,j); } cout<<tot<<endl; memset(g,1,sizeof(g)); tot=0;//建筑物数量 for(i=1;i<=n;i++) { for(j=1;j<=m;j++) if(s[i][j]!='.')//记录每个建筑物的信息 { tot++; a[1][tot]=i;//横坐标 a[2][tot]=j;//纵坐标 } } for(i=1;i<=tot;i++)//建图(每个点都建 属于一个城市的不同桥) for(j=i+1;j<=tot;j++) { if(a[1][i]!=a[1][j]&&abs(a[2][i]-a[2][j])<=1)//如果符合连桥的条件 { g[i][j]=abs(a[1][i]-a[1][j])-1; g[j][i]=g[i][j]; } else if(a[2][i]!=a[2][j]&&abs(a[1][i]-a[1][j])<=1) { g[i][j]=abs(a[2][i]-a[2][j])-1; g[j][i]=g[i][j]; } } memset(minn,1,sizeof(minn)); minn[1]=0; for(i=1;i<=tot;i++)//跑 Prim { k=0; for(j=1;j<=tot;j++) if(f[j]==0&&minn[j]<minn[k]) k=j; f[k]=1; for(j=1;j<=tot;j++) if(f[j]==0&&minn[j]>g[k][j]) minn[j]=g[k][j]; } for(i=1;i<=tot;i++) { if(minn[i]!=0&&minn[i]<1000000) { bb++;//统计桥的个数 sum=sum+minn[i];//累加桥的长度 } } cout<<endl<<bb<<" "<<sum; return 0; }