//终于A了这道让我难受的题
1002 搭桥
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题解
题目描述 Description
有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。
输入描述 Input Description
在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= r <= 50 and 1 <= c <= 50). 接下来的r 行, 每一行由c 个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。
输出描述 Output Description
在输出的数据中有两行,第一行表示建筑物的数目。第二行输出桥的数目和所有桥的总长度。
样例输入 Sample Input
样例1
3 5
…
..#..
…
样例2
3 5
…
…..
….#
样例3
3 5
.
.#.
.
样例4:
3 5
.#..
…..
….#
样例输出 Sample Output
样例1
5
4 4
样例2
2
0 0
样例3
1
0 0
样例4
3
1 1
一开始看这题目标签 最小生成树 ??一脸懵逼
这哪里是最小生成树了啊喂。。
后来吧 实在看它不顺眼 实在想A了它换个√看,,
于是乎 认真读题+开脑洞后 (不得不承认有些题真的需要开一开脑洞)
大概看懂了题的意思
现在我自己来描述一遍
一个平面上有若干个点 若干个点相连(八个方向相连)形成一座城市
这些城市之间仅能水平或竖直联通(道路不能拐弯) 求城市个数及能够将各个城市连起来的道路最小总长度 ;
那么现在很显然 第一个问题dfs或bfs处理每个点就可以了
第二个问题 最小生成树当然kruskal最简单 问题是怎么求出各个城市间的道路和道路长度 因为仅能水平或竖直连通两个城市 所以直接分别纵向和横向枚举,记录当前到达的点有没有城市,如果有城市那么是不是非记录的城市 如果是那么存下当前记录城市到该点城市的距离,当前已走过的距离刷新为0,更新当前城市为该点城市;
然而这样只有60分
因为并没有考虑全面
给定的平面图是一个矩形方阵 因此上下两行(或者左右两列)城市之间也可以有道路连接 因此每次判断要加上某点下一行(或下一列)的点;
现在是80分了
为啥还不对咯。。
考虑这样的一种情况:
|1■| □| □|
| □| □|2■|
| □|3■| □|
按照上面的思路(枚举记录)来说 1到2的距离是可以算出来并记录下来的 然而3到2也应该是能连接的 但是实际上并没有算出3到2的距离;
如果会出现这种情况 那么3一定是在2的下一行并且列数在2的前面
所以直接把原来的正向枚举反过来再枚举一遍不就好了??
所以 我复制后并稍微改了一下一开始的枚举点的代码,~(更暴力了一些。。) ~
100。
(我感觉你不会想看代码的。。)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdlib>
#include<cmath>
#include<set>
using namespace std;
int n,m,tu[60][60],visit[60][60],map[60][60],p,pp,sum,longer,fa[3000];
int zx[9]={0,1,1,1,0,0,-1,-1,-1},
zy[9]={0,0,1,-1,-1,1,-1,0,1};
struct rec{
int from,to,w;
}e[500001];
void dfs(int x,int y)
{
map[x][y]=p;
visit[x][y]=1;
for(int i=1;i<=8;i++)
{
int tx=zx[i]+x,ty=zy[i]+y;
if(!visit[tx][ty]&&tu[tx][ty])
{
dfs(tx,ty);
}
}
}
bool cmp(rec a,rec b)
{
return a.w<b.w;
}
int find(int a){
if(fa[a]==a)return a;
return fa[a]=find(fa[a]);
}
void kruskal()
{
for(int i=1;i<=p;i++)
{
fa[i]=i;
}
sort(e+1,e+pp+1,cmp);
for(int i=1;i<=pp;i++)
{
if(find(e[i].to)!=find(e[i].from))
{
fa[find(e[i].to)]=find(e[i].from);
//find(e[i].to);
sum++;
longer+=e[i].w;
}
}
}
void makedis()
{
int dis=0,now=0;
for(int i=1;i<n;i++)
{
now=0,dis=0;
for(int j=1;j<=m;j++)
{
if(map[i][j])
{
if(now==0)
{
now=map[i][j];
dis=0;
}
else {
if(map[i][j]&&map[i][j]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i][j];
e[pp].w=dis;
dis=0;
now=map[i][j];
}
}
}
else if(map[i+1][j])
{
if(now==0)
{
now=map[i+1][j];
dis=0;
}
else {
if(map[i+1][j]&&map[i+1][j]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i+1][j];
e[pp].w=dis;
dis=0;
now=map[i+1][j];
}
}
}
else dis++;
}
}
for(int i=1;i<n;i++)
{
now=0,dis=0;
for(int j=m;j>=1;j--)
{
if(map[i][j])
{
if(now==0)
{
now=map[i][j];
dis=0;
}
else {
if(map[i][j]&&map[i][j]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i][j];
e[pp].w=dis;
dis=0;
now=map[i][j];
}
}
}
else if(map[i+1][j])
{
if(now==0)
{
now=map[i+1][j];
dis=0;
}
else {
if(map[i+1][j]&&map[i+1][j]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i+1][j];
e[pp].w=dis;
dis=0;
now=map[i+1][j];
}
}
}
else dis++;
}
}
for(int j=1;j<m;j++)
{
dis=0,now=0;
for(int i=n;i>=n;i--)
{
if(map[i][j])
{
if(now==0)
{
now=map[i][j];
dis=0;
}
else {
if(map[i][j]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i][j];
e[pp].w=dis;
dis=0;
now=map[i][j];
}
}
}
else if(map[i][j+1])
{
if(now==0)
{
now=map[i][j+1];
dis=0;
}
else {
if(map[i][j+1]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i][j+1];
e[pp].w=dis;
dis=0;
now=map[i][j+1];
}
}
}
else dis++;
}
}
for(int j=1;j<m;j++)
{
dis=0,now=0;
for(int i=1;i<=n;i++)
{
if(map[i][j])
{
if(now==0)
{
now=map[i][j];
dis=0;
}
else {
if(map[i][j]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i][j];
e[pp].w=dis;
dis=0;
now=map[i][j];
}
}
}
else if(map[i][j+1])
{
if(now==0)
{
now=map[i][j+1];
dis=0;
}
else {
if(map[i][j+1]!=now)
{
pp++;
e[pp].from=now;
e[pp].to=map[i][j+1];
e[pp].w=dis;
dis=0;
now=map[i][j+1];
}
}
}
else dis++;
}
}
}
int main()
{
//ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char c;
cin>>c;
if(c=='#')tu[i][j]=1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!visit[i][j]&&tu[i][j])
{
p++;
dfs(i,j);
}
}
}
cout<<p<<"\n";
makedis();
kruskal();
cout<<sum<<" "<<longer;
return 0;
}