zoukankan      html  css  js  c++  java
  • 搭桥

    Codevs 1002 搭桥

    时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 黄金 Gold
     
    题目描述 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

    数据范围及提示 Data Size & Hint

    见描述

    分类标签 Tags 点此展开 

     
    思路:
      dfs+最小生成树。
      从第一个点向四个方向搜索扩展,记录下方向和距离(指向点,被指向点,权值),跑一遍最小生成树,输出答案
    (⊙v⊙)嗯~ 代码:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n,m,num,zh,ncon,ans=0;
    char cmap[51][51];
    int dad[50101],imap[51][51];
    const int dx[9]={0,-1,-1,0,1,1,1,0,-1};
    const int dy[9]={0,0,1,1,1,0,-1,-1,-1};
    
    struct Edge{
        int pre,to,dis;
    }edge[5000001]; //数组开大 
    
    int Find(int x) {
        if(x==dad[x]) return x;
        dad[x] = Find(dad[x]);
        return dad[x]; 
    }
    
    void big(int x,int y,int dis) {
        imap[x][y] = dis;
        for(int i=1; i<=8; i++) {
            if(x+dx[i]>0&&x+dx[i]<=n&&y+dy[i]>0&&y+dy[i]<=m) {
                if(imap[x+dx[i]][y+dy[i]]==-1) {
                    big(x+dx[i],y+dy[i],dis);
                }
            }
        }
    }
    
    int cmp(struct Edge a,struct Edge b) {
        return a.dis < b.dis;
    }
    
    void edge_add(int pre,int to,int dis) {  
        num++; //记录边数 
        edge[num].pre = pre;
        edge[num].to = to;
        edge[num].dis = dis;
    }
    
    void edge_find_up(int x,int y,int pre,int dis) { //向上找 
        if(y-1>0&&x-1>0) if(imap[x-1][y-1]!=0&&imap[x-1][y-1]!=pre) edge_add(pre,imap[x-1][y-1],dis);
        if(y+1<=m&&x-1>0) if(imap[x-1][y+1]!=0&&imap[x-1][y+1]!=pre) edge_add(pre,imap[x-1][y+1],dis);
        if(x-1>0){
            if(imap[x-1][y]!=0&&imap[x-1][y]!=pre) edge_add(pre,imap[x-1][y],dis);
            else if(imap[x-1][y]!=pre) edge_find_up(x-1,y,pre,dis+1);
        }
    }
    
    void edge_find_down(int x,int y,int pre,int dis) { //向下找 
        if(y-1>0&&x+1<=n) if(imap[x+1][y-1]!=0&&imap[x+1][y-1]!=pre) edge_add(pre,imap[x+1][y-1],dis);
        if(y+1<=m&&x+1<=n) if(imap[x+1][y+1]!=0&&imap[x+1][y+1]!=pre) edge_add(pre,imap[x+1][y+1],dis);
        if(x+1<=n){
            if(imap[x+1][y]!=0&&imap[x+1][y]!=pre) edge_add(pre,imap[x+1][y],dis);
            else if(imap[x+1][y]!=pre) edge_find_down(x+1,y,pre,dis+1);
        }
    }
    
    void edge_find_left(int x,int y,int pre,int dis) {  //向左找 
        if(y-1>0&&x-1>0) if(imap[x-1][y-1]!=0&&imap[x-1][y-1]!=pre) edge_add(pre,imap[x-1][y-1],dis);
        if(y-1>0&&x+1<=n) if(imap[x+1][y-1]!=0&&imap[x+1][y-1]!=pre) edge_add(pre,imap[x+1][y-1],dis);
        if(y-1>0){
            if(imap[x][y-1]!=0&&imap[x][y-1]!=pre) edge_add(pre,imap[x][y-1],dis);
            else if(imap[x][y-1]!=pre) edge_find_left(x,y-1,pre,dis+1);
        }
    }
    
    void edge_find_right(int x,int y,int pre,int dis) { //向右找 
        if(y+1<=m){  
            if(imap[x][y+1]!=0&&imap[x][y+1]!=pre) edge_add(pre,imap[x][y+1],dis);//如果右边有城市并且与当前城市不是同一个城市,就建桥 
            else if(imap[x][y+1]!=pre) edge_find_right(x,y+1,pre,dis+1); //如果两个城市之间的距离是大于1的,继续找 
        }
        if(y+1<=m&&x-1>0) if(imap[x-1][y+1]!=0&&imap[x-1][y+1]!=pre) edge_add(pre,imap[x-1][y+1],dis);//如果右边的上方有城市并且与当前城市不是同一个城市,就建桥 
        if(y+1<=m&&x+1<=n) if(imap[x+1][y+1]!=0&&imap[x+1][y+1]!=pre) edge_add(pre,imap[x+1][y+1],dis); //如果右边的下方有城市并且与当前城市不是同一个城市,就建桥 
        
    }
    
    void edge_build(int pre,int x,int y) {  //向四个方向查询 
        if(x-1>0) edge_find_up(x-1,y,pre,1);
        if(x+1<=n) edge_find_down(x+1,y,pre,1);
        if(y-1>0) edge_find_left(x,y-1,pre,1);
        if(y+1<=m) edge_find_right(x,y+1,pre,1);
    }
    
    int main() {
        cin>>n>>m;
        for(int i=1; i<=n; i++){
            cin>>cmap[i]+1;
            for(int j=1; j<=m; j++) {
                if(cmap[i][j]=='#') imap[i][j]=-1;
            }
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                if(imap[i][j]==-1) {
                    ncon++; //记录城市数 
                    big(i,j,ncon); //处理初始图为一个连通块的情况 
                }
            }
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                if(imap[i][j]!=0) edge_build(imap[i][j],i,j);
            }
        }sort(edge+1,edge+num+1,cmp);
        int head=0,zh=0,xx,yy;
        for(int i=1; i<=ncon; i++) dad[i] = i;
        while(head<=ncon&&zh<=num) {
            zh++;
            xx=Find(edge[zh].pre),yy=Find(edge[zh].to);
            if(xx!=yy) {
                ans+=edge[zh].dis; 
                dad[xx] = yy;
                head++;
            }
        }
        cout<<ncon<<endl<<head<<" "<<ans<<endl;
        return 0;
    }

    自己选的路,跪着也要走完!!!

  • 相关阅读:
    为什么 execute(`echo 中文`) 输出中文源码?
    使用图片跨域方式获取图片数据 使用 jsonp 方式跨域获取数据
    js 中的 sleep 方法, 阻塞式
    大数据存储单位介绍(TB、PB、EB、ZB、YB有多大)
    在 chrome 开发工具中使用终端
    作为一个代码搬运工,如何应对突如其来的灵魂拷问『你今天做了什么』?
    JVM相关
    python和C++联合调试
    Google protobuf解析消息逻辑的版本问题
    卷积转换为矩阵运算中填充数的计算-GEMM
  • 原文地址:https://www.cnblogs.com/wsdestdq/p/6842689.html
Copyright © 2011-2022 走看看