1. 程式人生 > >Code VS 1002 搭橋

Code VS 1002 搭橋

return 方法 input 技術 區域 pri 距離 [] log

題目描述 Description

有一矩形區域的城市中建築了若幹建築物,如果某兩個單元格有一個點相聯系,則它們屬於同一座建築物。現在想在這些建築物之間搭建一些橋梁,其中橋梁只能沿著矩形的方格的邊沿搭建,如下圖城市1有5棟建築物,可以搭建4座橋將建築物聯系起來。城市2有兩座建築物,但不能搭建橋梁將它們連接。城市3只有一座建築物,城市4有3座建築物,可以搭建一座橋梁聯系兩棟建築物,但不能與第三座建築物聯系在一起。

技術分享

輸入描述 Input Description

在輸入的數據中的第一行包含描述城市的兩個整數rc, 分別代表從北到南、從東到西的城市大小(1 <= r <= 50 and 1 <= c

<= 50). 接下來的r 行, 每一行由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 搭橋