hihocoder [Offer收割]編程練習賽12 [1495] ---- 矩形分割

原題連接

矩形分割ios

算法分析:算法

解決該題要用到「並查集」的思想。數組

這裏有一篇不錯的博客介紹並查集: 並查集(Union-Find)算法介紹函數

記 int total=N*M,這裏會有 total 個方塊,由於一道對角線(''或者'/')會把一塊方塊分割爲左右兩部分,因此,咱們把任意一塊方塊看作左右兩個部分。對於左部分,從左到右從上到下依次編號爲 0~total-1;對於右部分,從作到右從上到下依次編號爲 total~2*total-1;用一個 int parent[20000] (由於1<=N,M<=100; 全部最多有10000個方塊,也就是最多有20000個半部分) 的數組來記錄一個部分所屬於的集合編號。初始化 parent[i]=i;spa

C++算法實現.net

#include<iostream>
using namespace std;


int find(int parent[], int i) {
    int p = parent[i];
    if (p != i) {
        parent[i] = find(parent, p);//若是當前節點的編組號不是自身,那麼遞歸查詢到當前編組的根節點,並修改當前節點的編組號爲該編組的根節點
    }
    return parent[i];//返回當前節點的編組號
}

void unit(int parent[], int i, int j)//合併兩個編組
{
    int pi = find(parent, i);
    int pj = find(parent, j);
    if (pi != pj)
    {
        if (pi < pj) {//將編組號小的根節點做爲根,另外一個編組掛接到該編組上
            parent[pj] = pi;
        }
        else {
            parent[pi] = pj;
        }
    }
}


int main(int argc, char* argv[])
{

    int N, M, index, total;
    char wall[101][101];//牆面數據
    int parent[20000];//parent[0~total-1] 爲左半部分的並查集信息,parent[total~2*total-1]爲右半部分的並查集信息

    cin >> N >> M;


    cin.getline(wall[0], 101);// N 和 M 獨佔一行,後面的換行符沒有從輸入緩衝中去除掉,會影響 cin.getline()函數的結果,所以調用一次 cin.getline(wall[0],101)來去除掉該換行符
    for (int i = 0; i < N; i++) {
        cin.getline(wall[i], 101);
    }

    total = N*M;//正方形數量
    for (int i = 0; i < total; i++) {//初始化並查集
        parent[i] = i;
        parent[total + i] = total + i;
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            index = i*M + j;//正方形(i,j)左半部分在 parent 中所對應的下標
            switch (wall[i][j]) {
            case ' ':
                if (i > 0) {//若是該正方形上方還有正方形,則將該正方形和上方正方形所屬於的組進行合併
                    switch (wall[i - 1][j]) {
                    case ' ':
                    case '\\':
                        unit(parent, index, index - M);//index-M 爲當前正方形上方的正方形左半部分在 parent[] 中的下標
                        break;
                    case '/':
                        unit(parent, index, total + index - M);//total+index-M 爲當前正方形上方的正方形右半部分在 parent[] 中的下標
                        break;
                    default:
                        return -1;
                        break;
                    }
                }
                if (j > 0) {
                    //當前正方形左面還有正方形,則合併當前正方形左半部分和左面正方形的右半部分
                    unit(parent, index, total + index - 1);
                }
                unit(parent, total + index, index);//由於當前正方形沒有被分割,因此當前正方形的左右兩半部分一定屬於同一個組,合併之
                //另外因爲當前正方形內容爲空格,因此當前正方形右邊的正方形和下邊的正方形必然會跟當前正方形相鏈接,在後續的處理步驟中天然會合並它們,因此無需考慮當前正方形右面正方形和下面正方形的內容
                break;
            case '\\':
                
                //當前正方形的左半部分有可能跟左面正方形的右半部分、下面正方形的左半部分或右半部分相接;對應if(j>0)和if(i<N-1)的狀況
                if (j > 0) {
                    unit(parent, index, total + index - 1);
                }
                if (i<N - 1) {
                    switch (wall[i + 1][j]) {
                    case ' ':
                    case '/':
                        unit(parent, index, index + M);
                        break;
                    case '\\':
                        unit(parent, index, total + index + M);
                        break;
                    default:
                        return -1;
                        break;
                    }
                }
                //當前正方形的右半部分可能跟上面正方形的左半部分或右半部分、右面正方形的左半部分相鏈接;對應if(i>0)和if(j<M-1)的狀況
                if (i>0) {
                    switch (wall[i - 1][j]) {
                    case ' ':
                    case '\\':
                        unit(parent, total + index, index - M);
                        break;
                    case '/':
                        unit(parent, total + index, total + index - M);
                        break;
                    default:
                        return -1;
                        break;
                    }
                }
                if (j < M - 1) {
                    unit(parent, total + index, index + 1);
                }
                break;
            case '/':
                //當前正方形的左半部分可能跟上面正方形的左半部分或右半部分、左面正方形的右半部分相鏈接;對應 if(i>0) 和 if(j>0) 的情形
                if (i > 0) {
                    switch (wall[i - 1][j]) {
                    case ' ':
                    case '\\':
                        unit(parent, index, index - M);
                        break;
                    case '/':
                        unit(parent, index, total + index - M);
                        break;
                    default:
                        return -1;
                        break;
                    }
                }
                if (j > 0) {
                    unit(parent, index, total + index - 1);
                }

                //當前正方形的右半部分可能跟右面正方形的左半部分、下面正方形的左半部分或右半部分相鏈接;對應 if(j<M-1) 和  if(i<N-1) 的狀況
                if (j < M - 1) {
                    unit(parent, total + index, index + 1);
                }
                if (i < N - 1) {
                    switch (wall[i + 1][j]) {
                    case ' ':
                    case '/':
                        unit(parent, total + index, index + M);
                        break;
                    case '\\':
                        unit(parent, total + index, total + index + M);
                        break;
                    default:
                        return -1;
                        break;
                    }
                }
                break;
            default:
                return -1;
                break;
            }
        }
    }

    int ceil = total << 1;
    int count = 0;
    for (int i = 0; i < ceil; i++) {
        if (parent[i] == i) {//若是 parent[i]==i ,那麼 i 爲其所在的編組的根節點
            count++;
        }
    }
    cout << count;
    return 0;
}
相關文章
相關標籤/搜索