Code VS 1002 搭橋
有一矩形區域的城市中建築了若幹建築物,如果某兩個單元格有一個點相聯系,則它們屬於同一座建築物。現在想在這些建築物之間搭建一些橋梁,其中橋梁只能沿著矩形的方格的邊沿搭建,如下圖城市1有5棟建築物,可以搭建4座橋將建築物聯系起來。城市2有兩座建築物,但不能搭建橋梁將它們連接。城市3只有一座建築物,城市4有3座建築物,可以搭建一座橋梁聯系兩棟建築物,但不能與第三座建築物聯系在一起。
輸入描述 Input Description
在輸入的數據中的第一行包含描述城市的兩個整數r 和c, 分別代表從北到南、從東到西的城市大小(1 <= r <= 50 and 1 <= c
輸出描述 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 搭橋