1002 搭桥
有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。
在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= r <= 50 and 1 <= c <= 50). 接下来的r行, 每一行由c 个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。
在输出的数据中有两行,第一行表示建筑物的数目。第二行输出桥的数目和所有桥的总长度。
样例1
3 5
#...#
..#..
#...#
样例2
3 5
##...
.....
....#
样例3
3 5
#.###
#.#.#
###.#
样例4:
3 5
#.#..
.....
....#
样例1
5
4 4
样例2
2
0 0
样例3
1
0 0
样例4
3
1 1
见描述
这题我真心没觉得有多模板题,一些细节也很坑,至少我是嗑了很久,说是模板题的大爷们我先献上膝盖:)。
这道题挺神奇的,比如我这种辣鸡第一眼就没看出是最小生成树,最后乱搞碰壁才发现可以写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!