計蒜客模擬賽第九題
在一個 n×m 的方格地圖上,某些方格上放置着炸彈。手動引爆一個炸彈以後,炸彈會把炸彈所在的行和列上的所有炸彈引爆,被引爆的炸彈又能引爆其他炸彈,這樣連鎖下去。
現在爲了引爆地圖上的所有炸彈,需要手動引爆其中一些炸彈,爲了把危險程度降到最低,請算出最少手動引爆多少個炸彈可以把地圖上的所有炸彈引爆。
輸入格式
第一行輸兩個整數 n, m,用空格隔開。
接下來 n 行,每行輸入一個長度爲 m 的字符串,表示地圖信息。0表示沒有炸彈,1表示炸彈。
數據約定:
對於60% 的數據: 1≤n,m≤100;
對於 100% 的數據: 1≤n,m≤1000;
數據量比較大,不建議用cin輸入。
輸出格式
輸出要手動引爆的炸彈數。
分析
1.看到這道題我的思路是首先我需要確定炸彈的個數,以及每個炸彈所對應的座標,由於用到橫縱座標兩個參數,所以考慮決定選用結構體構建炸彈的點.
2.根據題目給定的要求需要以字符串,所以決定採用字符數組更爲合理,char類型,即輸入採用二維數組,根據所給定的m,n進行。
3.對於每一顆炸彈,他均有兩個參數,分別是行號和列號,對於所有的炸彈遍歷我們將按照,橫縱座標任意一個值相同我們將他們連接起來,然後我們將炸彈形成連通圖
4.對於不同的炸彈不同的老大大大哥,所以將這些炸彈的大哥哥,放入棧內,最後去重,得到的vector長度即爲最終的最優答案
代碼實現
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;//首先記錄 炸彈即 1 存在的位置座標
#define Max 1000
char a[Max][Max];//每行可以容納的數量
int pre[Max];
int k = 0;
struct Node
{
int x;
int y;
}p[100];//100個炸彈點
int find(int x)
{
int r = x;
while (r != pre[r])
r = pre[r];
int i = x, j;
while (i != r)//路徑壓縮
{
j = pre[i]; // 在改變上級之前用臨時變量 j 記錄下他的值
pre[i] = r; //把上級改爲根節點
i = j;
}
return r;
}
int main()
{
vector<int> elem;
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> a[i][j];
if (a[i][j] == '1')//記錄炸彈,並且統計炸彈的個數
{
k++;
p[k].x = i;
p[k].y = j;
}
}
}
//炸彈的初始化,設置他們的前驅結點均爲自己
for (int i = 1; i <= k; i++)
{
pre[i] = i;
}
//如果任意兩個炸彈的 橫或者縱座標相同則連接兩個點
for (int i = 1; i <= k; i++)
{
for (int j = i + 1; j <= k; j++)
{
if (p[i].x == p[j].x || p[i].x == p[j].y)
{
pre[j] = i;
}
}
}
//將每個炸彈的大大大哥找到,壓入棧內
/*記錄每個1的座標然後對相同的座標進行爆破,行座標相同直接爆破,縱座標相同直接爆破*/
for (int i = 1; i <= k; i++)
{
elem.push_back(find(i));
}
//排序
sort(elem.begin(), elem.end());
elem.erase(unique(elem.begin(), elem.end()),elem.end());//unique()函數將重複的元素放置在最後
//erase將重複的第一個元素開始,到最後一個元素開始,全部擦除
cout << elem.size() << endl;//數字的種類既是最終的答案
/*
for (int i = 1; i <= k; i++)//前驅驗證
{
cout << "第" << i << "個的前驅" << pre[i] << endl;
}*/
/*得到最終的炸彈個數*/
//cout << k << endl;
return 0;
}
歡迎大家與我交流,並提出意見和建議,我將進行進一步優化和處理