codevs1002 搭桥

1002 搭桥

 
题目描述  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

 

这个题,跃跃欲试了好久,今天终于AC

为什么看起来复杂?因为图形是放在格子里,这就说明每个建筑物有四个角,怎么办,蒙圈?

不如将其看做一个点,一步一步写

下面是一些类似代码解释的东西

以字符串的形式输入地图的每一行
统计地图中的建筑物数量
把所有点的父亲都初始化为自己(依次编号)
遍历整个地图
遇到不是楼房的点则跳过
找到一个楼房,则以该楼房为中心,再对地图进行一次遍历,同样跳过不是楼房的点
跳过本行以上行的点(已经遍历过),跳过同行且本列以前的点(已经遍历过)
找到目标点(有用的点),并用其在地图上的序号标示
对两个建筑判断能否搭桥
find_bright函数: 排除直接相邻的两点(不用搭桥)
排除斜相邻的点(不用搭桥)
返回-1是不用搭桥,返回0是无法搭桥
在同行或同列可以搭桥,sign是这座桥的长度
犹如加边,把建筑物连起来
最终再统计一遍桥的数目和总长

就是这样

然后再来一点注意事项

1 编号方法如图

 

2.如图,这是边的由来

3.如图,这是为什么find_bridge函数中用到fabs(x-x1)<=1

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int buildnum,bridnum,n,m,map[60][60],father[361],lianjie,bridge;
int e_num;
struct node{
    int v,to,from;
}e[1000000];
char s[60];
int find_bridge(int x,int y,int x1,int y1){
    if(x==x1&&(fabs(x-x1)==1))return -1;
    if(y==y1&&(fabs(y-y1)==1))return -1;
    if((fabs(x-x1)==1)&&(fabs(y-y1)==1))return -1;
    if(fabs(x-x1)<=1)return fabs(y-y1)-1;
    if(fabs(y-y1)<=1)return fabs(x-x1)-1;
    return 0;
}
int find(int x){
    if(father[x]==x)return father[x];
    return father[x]=find(father[x]);
}
int connect(int p1,int p2){
    int f1=find(p1);
    int f2=find(p2);
    father[f1]=f2;
}
int cmp(node i,node j){
    return i.v<j.v;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        for(int j=1;j<=m;j++){
            if(s[j-1]=='.')map[i][j]=0;
            if(s[j-1]=='#')map[i][j]=1,buildnum++;
        }
    }
    for(int i=1;i<=n*m;i++)father[i]=i;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(map[i][j]==0)continue;
            for(int x=i;x<=n;x++){
                for(int y=1;y<=m;y++){
                    if(x==i&&y<=j)continue;
                    if(map[x][y]==0)continue;
                    int it=find_bridge(i,j,x,y);
                    int one=(i-1)*m+j,two=(x-1)*m+y;
                    if(it==-1){
                        if(find(one)!=find(two))connect(one,two),lianjie++;
                        continue;
                    }
                    if(it==0)continue;
                    //加边 
                    e[++e_num].from=one;
                    e[e_num].to=two;
                    e[e_num].v=it;
                }
            }
        }
    }
    printf("%d\n",buildnum-lianjie);
    sort(e+1,e+e_num+1,cmp);
    for(int i=1;i<=e_num;i++){
        if(find(e[i].from)!=find(e[i].to))
        connect(e[i].from,e[i].to),bridge+=e[i].v,bridnum++;
    }
    printf("%d %d",bridnum,bridge);
} 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值