题目描述 Description

有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。

输入描述 Input Description

在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= <= 50 and 1 <=  c <= 50). 接下来的r 行, 每一行由个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。

输出描述 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

-----------------------------------------------------------------------------------------------------------------(分割线)

弄了几乎快2个半小时..............

主要是在建图上.......................

一开始居然连题目都看不懂.....

¥%&%#@……%&&%¥%......

 

思路:

这题,主要是dfs+最小生成树,算法是简单.....但建图不好建。

这题第一问很明显是求联通块的个数。

第二问是要求最小生成树,边及其长度总和。

因为联通块不是一个整体,所以需要做的事是求每个联通块间的最小距离。

这里说两种方法。

第一种,开四重循环,枚举点对,然后每次都更新联通块间的最小距离。

第二种,扫描法,枚举每一个城市点,然后以六个方向进行扫描(听着代码长度就不会少),然后每次扫描都更新某两联通块间的距离。

    假设当前枚举的点是(x,y) , 则这六个方向为:  (x,i),(x+1,i) (x-1,i) ,(y,i),(y+1,i),(y-1,i),每次扫描到和当前点的联通块编号不相等的点时就更新最小距离。

 

我用的是第二种,觉得第一种没挑战性...........

下面代码的g[i][j]表示联通块编号i与联通块编号为j的最小距离。

有问题留言。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 60
#define M 250900
using namespace std; int G[N][N]; //图数组 int en,n,r,c; //边数,联通块个数,题目所描述的,r,c。 struct edge{
int s,e,d;
}ed[M]; bool operator < (const edge &a, const edge &b){ //重载运算符
return a.d < b.d;
} void add_edge(int s,int e,int d){ //建边
en++;
ed[en].s= s,ed[en].e =e ,ed[en].d = d;
}
int fa[M]; int getf(int now){ //并查集
if(now == fa[now])return now;
else return fa[now] = getf(fa[now]);
} void kruskal(){ //kruskal算法
sort(ed+,ed+en+);
for(int a = ; a <= n; a++)fa[a] = a;
int ans = ,num = ;
for(int a = ; a <= en; a++){
int f1 = getf(ed[a].s);
int f2 = getf(ed[a].e);
if(f1 != f2){
fa[f1] = f2;
ans += ed[a].d;
num++;
}
}
printf("%d %d\n",num,ans);
} int tx[] = {,,,,-,-,,-};
int ty[] = {,-,,-,,-,,}; void dfs(int x,int y){ //求联通块
G[x][y] = n;
for(int i = ; i < ; i++){
int xx = tx[i]+x;
int yy = ty[i]+y;
if(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] == -))
dfs(xx,yy);
}
} int g[][]; void cread(int x,int y){ //将六个方向再细分,变成十二个方向(笑...)
int xx,yy;
xx = x+,yy = y+;;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],yy-y-);
yy++;
}
yy = y-;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],y-yy-);
yy--;
}
xx = x,yy = y+;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],yy-y-);
yy++;
}
yy = y-;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],y-yy-);
yy--;
}
xx = x-,yy = y+;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],yy-y-);
yy++;
}
yy = y-;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],y-yy-);
yy--;
} yy = y,xx = x+;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],xx-x-);
xx++;
}
xx = x-;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],x-xx-);
xx--;
}
yy = y+,xx = x+;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],xx-x-);
xx++;
}
xx = x-;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],x-xx-);
xx--;
}
yy = y-;xx = x+;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],xx-x-);
xx++;
}
xx = x-;
while(xx >= && xx <= r && yy >= && yy <= c && (G[xx][yy] != G[x][y])){
if(G[xx][yy] != )g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],x-xx-);
xx--;
}
} int main(){
scanf("%d%d",&r,&c);
for(int i = ; i <= r; i++){
char s[];
scanf("%s",s);
for(int j = ; j < c; j++)
if(s[j] == '#')G[i][j+] = -;
else G[i][j+] = ;
}
for(int i = ; i <= r; i++){
for(int j = ; j <= c; j++){
if(G[i][j] == -){
n++;
dfs(i,j);
}
}
} memset(g,0x3f,sizeof(g)); printf("%d\n",n);
for(int i = ; i <= r; i++)
for(int j = ; j <= c; j++)
if(G[i][j] != )cread(i,j); for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
if(g[i][j] != g[][])add_edge(i,j,g[i][j]);
kruskal();
return ;
}

Code VS 1002 搭桥的更多相关文章

  1. codevs 1002 搭桥

    codevs 第一道题 先贴描述 1002 搭桥  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description ...

  2. 【wikioi】1002 搭桥(dfs+最小生成树)

    http://wikioi.com/problem/1002/ 今天开始又开始刷水了哈T_T.照着hzwer神犇的刷题记录刷!!! 题解: 一开始我也不会,但是我想到了直接爆搜T_T. 好吧,题解. ...

  3. codevs 1002 搭桥x

    题目描述 Description 有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物.现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建 ...

  4. 搭桥|codevs1002|最小生成树|Prim|并查集|Elena

    1002 搭桥  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点 ...

  5. 1、Codevs 必做:2833、1002、1003、2627、2599

    2833 奇怪的梦境  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description Aiden陷入了一个奇怪的梦境:他被困 ...

  6. 项目管理及自动构建工具Maven

    项目管理及自动构建工具Maven 一.Maven安装.目录结构.cmd命令1.下载安装apache-maven-3.2.3-bin.zip下载:http://maven.apache.org/down ...

  7. The WebSocket Protocol

      [Docs] [txt|pdf] [draft-ietf-hybi-t...] [Diff1] [Diff2] [Errata] Updated by: 7936 PROPOSED STANDAR ...

  8. PatentTips - Register file supporting transactional processing

    BACKGROUND OF THE INVENTION With the rise of multi-core, multi-threaded data processing systems, a k ...

  9. 开发者应该掌握 WebSocekt 协议的知识

    文章介绍 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它的出现使客户端和服务器之间的数据交换变得更加简单.WebSocket 通常被应用在实时性要求较高的场景,例如赛事数据. ...

随机推荐

  1. 0912MySQL 执行计划explain详解

    转自http://blog.itpub.net/29773961/viewspace-1767044/ 该博客内容是比较全的,虽然写的比较晦涩,多读几遍还是不错的 explain命令是查看查询优化器如 ...

  2. POJ 3710

    树的删边游戏.. 由于题目的特殊性,我们只需计算环的边数值.若为偶环,则直接把环的根节点置0.若为奇环,则留下一条边与根结点相连,并那它们的SG置0: 注意的是,两个点也可构成环,因为允许重边.所以, ...

  3. java 数组中求最值

    java中数组求最值,这在实际的开发中差点儿用不到,可是在面试中会偶尔被问到,这是考你主要的思维能力,如今说下这个题的基本思路 思路: 1:先定义一个变量,通常是用数组的第一个值 2:在循环中推断(从 ...

  4. HTML的表单form以及form内部标签

    <html> <head> <title> form表单的使用 </title> <!-- 标签名称:form 表单标签 属性:action:提交 ...

  5. DeepLearning to digit recognizer in kaggle

    DeepLearning to digit recongnizer in kaggle 近期在看deeplearning,于是就找了kaggle上字符识别进行练习.这里我主要用两种工具箱进行求解.并比 ...

  6. Java面试-Struts2

    1  Struts2工作原理 一个请求在Struts2框架中的处理大概分为下面几个步骤: 1.client初始化一个指向Servlet容器(比如Tomcat)的请求: 2.这个请求经过一系列的过滤器( ...

  7. Android5.1开机LOGO与开机动画【转】

    本文转载自:http://blog.csdn.net/u014770862/article/details/52624627 android5.1中,开机LOGO部分和之前版本的并不相同,主要区别在于 ...

  8. C++字符串与指针 所有的内容也就这么多了。

    1.定义一个字符串数组并初始化,然后输出其中的字符串. #include <iostream> using namespace std;int main(){ char str[]=&qu ...

  9. Hdu-6249 2017CCPC-Final G.Alice’s Stamps 动态规划

    题面 题意:给你n个集合,每个集合有L到R这些种类的邮票,让你选择其中的K个集合,使得最后选择的邮票种类尽可能多,N,L,R都<=2000 题解:容易乱想到网络流,可是再细想一下就会发现处理不了 ...

  10. H3BPM实例分享——金额规则大写

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...