Code VS 1002 搭桥

Posted WYBIACX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Code VS 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

 

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

 

弄了几乎快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+1,ed+en+1);
    for(int a = 1; a <= n; a++)fa[a] = a;
    int ans = 0,num = 0;
    for(int a = 1; 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[] = {0,0,1,1,-1,-1,1,-1};
int ty[] = {1,-1,1,-1,1,-1,0,0};

void dfs(int x,int y){                //求联通块 
    G[x][y] = n;
    for(int i = 0; i < 8; i++){
        int xx = tx[i]+x;
        int yy = ty[i]+y;
        if(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] == -1))
            dfs(xx,yy);
    }
}


int g[1009][1009];
 
void cread(int x,int y){            //将六个方向再细分,变成十二个方向(笑...) 
    int xx,yy;
    xx = x+1,yy = y+1;;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],yy-y-1);
        yy++;
    }
    yy = y-1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],y-yy-1);
        yy--;
    }
    xx = x,yy = y+1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],yy-y-1);
        yy++;
    }
    yy = y-1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],y-yy-1);
        yy--;
    }
    xx = x-1,yy = y+1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],yy-y-1);
        yy++;
    }
    yy = y-1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],y-yy-1);
        yy--;
    }
    
    yy = y,xx = x+1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],xx-x-1);
        xx++;
    }
    xx = x-1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],x-xx-1);
        xx--;
    }
    yy = y+1,xx = x+1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],xx-x-1);
        xx++;
    }
    xx = x-1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],x-xx-1);
        xx--;
    }
    yy = y-1;xx = x+1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],xx-x-1);
        xx++;
    }
    xx = x-1;
    while(xx >= 1 && xx <= r && yy >= 1 && yy <= c && (G[xx][yy] != G[x][y])){
        if(G[xx][yy] != 0)g[G[x][y]][G[xx][yy]] = min(g[G[x][y]][G[xx][yy]],x-xx-1);
        xx--;
    }
}

int main(){
    scanf("%d%d",&r,&c);
    for(int i = 1; i <= r; i++){
        char s[55];
        scanf("%s",s);
        for(int j = 0; j < c; j++)
            if(s[j] == \'#\')G[i][j+1] = -1;
            else G[i][j+1] = 0;
    }
    for(int i = 1; i <= r; i++){
        for(int j = 1; j <= c; j++){
            if(G[i][j] == -1){
                n++;
                dfs(i,j);
            }
        }
    }
    
    memset(g,0x3f,sizeof(g));
    
    printf("%d\\n",n);
    for(int i = 1; i <= r; i++)
      for(int j = 1; j <= c; j++)
         if(G[i][j] != 0)cread(i,j);
    
    for(int i = 1; i <= n; i++)
       for(int j = 1; j <= n; j++)
          if(g[i][j] != g[0][0])add_edge(i,j,g[i][j]);
    kruskal();
    return 0;
}

 

以上是关于Code VS 1002 搭桥的主要内容,如果未能解决你的问题,请参考以下文章

codevs1002 搭桥

CodeVS 1002-搭桥

codevs 1002 搭桥

codevs 1002 搭桥

VS code自定义用户代码片段snippet

vs code 自定义代码片段