zoukankan      html  css  js  c++  java
  • 搭桥|codevs1002|最小生成树|Prim|并查集|Elena

    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

    见描述


    这题我真心没觉得有多模板题,一些细节也很坑,至少我是嗑了很久,说是模板题的大爷们我先献上膝盖:)。

    这道题挺神奇的,比如我这种辣鸡第一眼就没看出是最小生成树,最后乱搞碰壁才发现可以写prim…

    坑点挺多的,而且题目本身也很迷。

    思路:无向图。第一问就是求联通块个数,可以用搜索水过,但是要注意“如果某两个单元格有一个点相联系,则它们属于同一座建筑物”,意思就是要搜索每个单元格的八个方向。后两问是建立在第一问上的。把相邻的建筑合成一个建筑来提高效率。我这里使用了并查集。在第一问的搜索中加入把相邻的建筑父亲都指向编号,比如第一组相邻的建筑合成的一个建筑编号为1,第二组编号为2…这就是把这些建筑缩为点,点的编号就是建筑组的编号。接下来考虑如何建边。建边也是这道题目的难点之一。我们可以发现对于每一个建筑,如果它上面那一行或者下面那一行有建筑的话,它们之间桥梁的距离就可以用横坐标相减再减1计算出来,而对于同一行的也是如此。对于每一列的也可以这样枚举。这里我用的是邻接矩阵存储图,注意存两个点之间的距离时要用min,因为你不知道这条边会不会比它已经存好的边短。建完图后我们就来跑Prim。有很多建筑组,而且这些建筑组之间不一定有边联通。以每个dis值还没确定的点为源点跑Prim,最后计算答案就可以了。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 const int inf=119999999;
      8 long long ans2,ans3;
      9 int n,m,f[40000],num[500][500],e[500][500],ans1,dis[40000];
     10 int D[8][2]={{0,1},{1,0},{0,-1},{-1,0},{-1,-1},{1,1},{1,-1},{-1,1}};
     11 bool map[500][500],map2[500][500],book[40000];
     12 int read()
     13 {
     14     int x=0,f=1; char c=getchar();
     15     while (c<'0' || c>'9') {if (c=='-') f=-1; c=getchar();}
     16     while (c>='0'&& c<='9') {x=x*10+c-'0'; c=getchar();}
     17     return (x*f);
     18 }
     19 int getf(int x)
     20 {
     21     if (f[x]==x) return x;
     22     f[x]=getf(f[x]);
     23     return f[x];
     24 }
     25 bool Merge(int a,int b)
     26 {
     27     a=getf(a); b=getf(b);
     28     if (a!=b) {
     29         return 1;
     30     }
     31     return 0;
     32 }
     33 void dfs(int x,int y)
     34 {
     35     num[x][y]=ans1;
     36     map2[x][y]=0;
     37     for (int i=0; i<=7; i++) {
     38         int xx=x+D[i][0],yy=y+D[i][1];
     39         if (xx>=1&&xx<=n&&yy>=1&&yy<=m&&map2[xx][yy]==1) {
     40             f[num[xx][yy]]=f[num[x][y]];
     41             dfs(xx,yy);
     42         }
     43     }
     44     return;
     45 }
     46 int main()
     47 {
     48     char c;
     49     n=read(); m=read();
     50     for (int i=1; i<=n; i++)
     51         for (int j=1; j<=m; j++) {
     52             cin>>c;
     53             if (c=='#') {
     54                 map[i][j]=1;
     55                 map2[i][j]=1;
     56             }
     57         }
     58     for (int i=1; i<=n; i++)
     59         for (int j=1; j<=m; j++)
     60             if (map2[i][j]==1) {
     61                 ans1++;
     62                 f[ans1]=ans1;
     63                 dfs(i,j);
     64             }
     65     if (ans1==1) {
     66         cout<<1<<endl<<0<<" "<<0<<endl;
     67         return 0;
     68     }
     69     for (int i=1; i<=ans1; i++)
     70         for (int j=1; j<=ans1; j++)
     71             e[i][j]=inf;
     72     for (int i=1; i<=n; i++) {
     73         for (int j=1; j<=m; j++) {
     74             if (map[i][j]==1) {
     75                 if (i!=1) {
     76                     for (int k=1; k<=m; k++)
     77                         if (map[i-1][k]==1 && Merge(num[i-1][k],num[i][j])) {
     78                             e[num[i-1][k]][num[i][j]]=min(e[num[i-1][k]][num[i][j]],abs(k-j)-1);
     79                             e[num[i][j]][num[i-1][k]]=e[num[i-1][k]][num[i][j]];
     80                         }
     81                 }
     82                 if (i!=n) {
     83                     for (int k=1; k<=m; k++)
     84                         if (map[i+1][k]==1 && Merge(num[i+1][k],num[i][j])) {
     85                             e[num[i+1][k]][num[i][j]]=min(abs(k-j)-1,e[num[i+1][k]][num[i][j]]);
     86                             e[num[i][j]][num[i+1][k]]=e[num[i+1][k]][num[i][j]];
     87                         }
     88                 }
     89                 for (int k=1; k<=m; k++)
     90                     if (map[i][k]==1 && Merge(num[i][k],num[i][j])) {
     91                         e[num[i][k]][num[i][j]]=min(abs(k-j)-1,e[num[i][k]][num[i][j]]);
     92                         e[num[i][j]][num[i][k]]=e[num[i][k]][num[i][j]];
     93                     }    
     94                 if (j!=1) {
     95                     for (int k=1; k<=n; k++)
     96                         if (map[k][j-1]==1 && Merge(num[k][j-1],num[i][j])) {
     97                             e[num[k][j-1]][num[i][j]]=min(abs(k-i)-1,e[num[k][j-1]][num[i][j]]);
     98                             e[num[i][j]][num[k][j-1]]=e[num[k][j-1]][num[i][j]];
     99                         }
    100                 }
    101                 if (j!=m) {
    102                     for (int k=1; k<=n; k++)
    103                         if (map[k][j+1]==1 && Merge(num[k][j+1],num[i][j])) {
    104                             e[num[k][j+1]][num[i][j]]=min(abs(k-i)-1,e[num[k][j+1]][num[i][j]]);
    105                             e[num[i][j]][num[k][j+1]]=e[num[k][j+1]][num[i][j]];
    106                         }
    107                 }
    108                 for (int k=1; k<=n; k++){
    109                         if (map[k][j]==1 && Merge(num[k][j],num[i][j])) {
    110                             
    111                             e[num[k][j]][num[i][j]]=min(abs(k-i)-1,e[num[k][j]][num[i][j]]);
    112                             e[num[i][j]][num[k][j]]=e[num[k][j]][num[i][j]];
    113                         }
    114                 }
    115             }
    116         }    
    117     }
    118     for (int i=1; i<=ans1; i++) {
    119         if (book[i]==0) {
    120             for (int j=1; j<=ans1; j++) dis[j]=inf;
    121             dis[i]=0;
    122             for (int k=1; k<ans1; k++) {
    123                 int MIN=inf,u;
    124                 for (int j=1; j<=ans1; j++)
    125                     if (book[j]==0&&dis[j]<MIN) {
    126                         MIN=dis[j];
    127                         u=j;
    128                     }
    129                 if (MIN==inf) break;
    130                 book[u]=1;
    131                 for (int j=1; j<=ans1; j++)
    132                     if (book[j]==0&&e[u][j]<dis[j]) dis[j]=e[u][j];
    133             }
    134             for (int j=1; j<=ans1; j++)
    135             if (dis[j]!=inf && dis[j]!=0) {
    136                 ans2++;
    137                 ans3+=dis[j];
    138             }
    139         }
    140     }    
    141     printf("%d
    %lld %lld
    ",ans1,ans2,ans3);
    142     return 0;
    143 }
    搭桥

    有问题可以直接在评论里面提问,有需要转载的请得到我的允许,否则按侵权处理。


    Elena loves NiroBC forever!
  • 相关阅读:
    LeetCode 112. Path Sum
    LeetCode 866. Prime Palindrome
    LeetCode 51.N-Queens
    【Codeforces 4D】Mysterious Present
    【Codeforces 158C】Cd and pwd commands
    【Codeforces 27A】Next Test
    【Codeforces 385C】Bear and Prime Numbers
    【Codeforces 474D】Flowers
    【Codeforces 1B】Spreadsheets
    【Codeforces 1114D】Flood Fill
  • 原文地址:https://www.cnblogs.com/AlenaNuna/p/7441795.html
Copyright © 2011-2022 走看看