Codevs 1002 搭桥

 CODEVS 1002 搭桥
解题报告
                         By MPS
----------------------------------------------------------------------------------------------------------------------------------------------------------
题目描述 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

分析:
   这道题目针对于第一问很明显是Flood_Fill,也就是DFS(不过要注意拓展八个方向)
   第二问就是最小生成树,统计最小生成树最多的边以及每条边的权值
   然后就AC了。。。
   这里注意!
      ①数组不能开50*50,要开1000*1000,出题人坑爹- -
      ②在一条边上即为可搭桥,否则权值为INF
   主要考察的就是选手的细心程度以及对搜索,最小生成树的掌握程度
代码:
   
#include <iostream>
using namespace std;
#include <cstdio>
#include <algorithm>
#include <cstring>

const int MaxN=1001;

struct city{
    int x,y;
}h[MaxN];

struct Edge{
    int u,v,w;
    friend bool operator< (Edge a,Edge b){return a.w<b.w;}
}map[MaxN*MaxN];

int hash[MaxN][MaxN],t[MaxN];
int n,m,L,s,ID=0;
char c[MaxN][MaxN];

void init(){
   cin>>n>>m;
   int i,j;
   for(i=1;i<=n;i++)
     for(j=1;j<=m;j++)
     {
        cin>>c[i][j];
        if(c[i][j]=='#'){//统计有多少个地皮 
            L++;//记录下来 
            h[L].x=i;
            h[L].y=j;
        }
    }
}

void Flood_fill(int x,int y,int ID){
    if(x<1 || y<1 || x>n || y>m || hash[x][y] || c[x][y]=='.')return;
     hash[x][y]=ID;
     if(x<n)Flood_fill(x+1,y,ID);
     if(y<m)Flood_fill(x,y+1,ID);
     if(x>1)Flood_fill(x-1,y,ID);
     if(y>1)Flood_fill(x,y-1,ID);
     if(x<n && y<m)Flood_fill(x+1,y+1,ID);
     if(x<n && y>1)Flood_fill(x+1,y-1,ID);
     if(x>1 && y>1)Flood_fill(x-1,y-1,ID);
     if(x>1 && y<m)Flood_fill(x-1,y+1,ID);
}

int find(int x){
    if(t[x]==-1)return x;
    else return t[x]=find(t[x]);
}

void Kruskal(){
    sort(map+1,map+s+1);
    int x,y,k=0,i=1,cost=0;
    while(i<=s){
        x=find(map[i].u);
        y=find(map[i].v);
        if(x!=y){
            cost+=map[i].w;
            k++;
            t[x]=y;
        }
        i++;
    }
    cout<<k<<" "<<cost;
}

int len(int x1,int y1,int x2,int y2){
	if(abs(x1-x2)<2)return abs(y1-y2)-1;
	if(abs(y1-y2)<2)return abs(x1-x2)-1;
	return 1000;
}

void add(int i,int j,int k,int l){
    s++;
    map[s].u=hash[i][j];
    map[s].v=hash[k][l];
    map[s].w=len(i,j,k,l);
}

void work(){
    int i,j,k,l;
    memset(hash,false,sizeof(hash));
    memset(t,-1,sizeof(t));//并查集 
    for(i=1;i<=L;i++)//对于每一块独立的地皮我们进行拓展 
      if(!hash[h[i].x][h[i].y])
        Flood_fill(h[i].x,h[i].y,++ID);//DFS填充
    cout<<ID<<endl;
    for(i=1;i<=n;i++)//统计地盘的距离 
     for(j=1;j<=m;j++)
      for(k=1;k<=n;k++)
        for(l=1;l<=m;l++)
          if(hash[i][j] && hash[k][l]&& !(i==k && j==l) && hash[i][j]!=hash[k][l])  
             add(i,j,k,l);
    Kruskal();//跑一遍最小生成树 
}

int main(){
   init();
   work();
   return 0;
}
也就100来行代码,还算比较好的。
-------------------------------------------------------Thanks for watching-------------------------------------------------------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值