團夥 並查集 題解 並查集 搜尋

2021-10-13 10:53:21 字數 3132 閱讀 9544

[1]1270海戰

題目描述

在這個著名的遊戲中,在乙個方形的盤上放置了固定數量和形狀的船隻,每只船卻不能碰到其它的船。在這個題中,我們僅考慮船是方形的,所有的船隻都是由圖形組成的方形。編寫程式求出該棋盤上放置的船隻的總數。

輸入輸入檔案頭一行由用空格隔開的兩個整數r和c組成,1< =r,c< =1000,這兩個數分別表示遊戲棋盤的行數和列數。接下來的r行每行包含c個字元,每個字元可以為「#」,也可為「.」,「#」表示船隻的一部分,「.」表示水。

輸出為每乙個段落輸出一行解。如果船的位置放得正確(即棋盤上只存在相互之間不能接觸的方形,如果兩個「#」號上下相鄰或左右相鄰卻分屬兩艘不同的船隻,則稱這兩艘船相互接觸了)。就輸出一段話「there are s ships.」,s表示船隻的數量。否則輸出「bad placement.」。

樣例輸入6 8

樣例輸出there are 5 ships.

提示思路

dfs連通塊, 套模板

void dfs(int x,int y);

int iy[5] = ;

int n,m,s;

char a[1005][1005];

bool check(int x,int y)//特判bad placement的情況{

int c(0);

if(a[x][y]=='#')

c++;

if(a[x+1][y]=='#')

c++;

if(a[x][y+1]=='#')

c++;

if(a[x+1][y+1]=='#')

c++;

if(c==3)

return 0;

return 1;

void dfs(int x,int y){

a[x][y]='.';

int i,j;

for(i = 1; i <= 4; i++){

int xx= x+ix[i];

int yy =y+iy[i];

if(xx>0 && xx<=n && yy>0 && yy<=m && a[xx][yy] == '#'){

dfs(xx,yy);

return ;

int main()

int i,j;

cin>>n>>m;

for(i=1;i<=n;i++)

for(j=1;j<=m;j++)

cin>>a[i][j];

for(i=1;i<=n;i++)

for(j=1;j<=m;j++)

if(i

cout<

return 0;

for(i=1;i<=n;i++)

for(j=1;j<=m;j++)

if(a[i][j]=='#')

s++;

dfs(i,j);

cout<

return 0;

​[2]2927 打擊犯罪(black)題目描述

某個地區有n(n≤1000)個犯罪團夥,當地**按照他們的危險程度由高到低給他們編號為1-n,他們有些團夥之間有直接聯絡,但是任意兩個團夥都可以通過直接或間接的方式聯絡,這樣這裡就形成了乙個龐大的犯罪集團,犯罪集團的危險程度由集團內的犯罪團夥數量唯一確定,而與單個犯罪團夥的危險程度無關(該犯罪集團的危險程度為n)。現在當地**希望花盡量少的時間(即打擊掉盡量少的團夥),使得龐大的犯罪集團分離成若干個較小的集團,並且他們中最大的乙個的危險程度不超過n/2。為達到最好的效果,他們將按順序打擊掉編號1到k的犯罪團夥,請程式設計求出k的最小值。

輸入第一行乙個正整數n。接下來的n行每行有若干個正整數,第乙個整數表示該行除第乙個外還有多少個整數,若第i行存在正整數k,表示i,k兩個團夥可以直接聯絡。

輸出乙個正整數,為k的最小值。

樣例輸入7

2 2 5

3 1 3 4

2 2 4

2 2 3

3 1 6 7

2 5 7

2 5 6

樣例輸出1

【提示】輸出1(打擊掉犯罪團夥)

思路需要注意題目裡說的是按順序打擊犯罪團夥,即從1開始打擊,要求k盡量小,因為要求犯罪危險程度小於n/2,因此用乙個陣列儲存,作為判斷依據,網上題解交代如果正向列舉要一直更新並查集,因此使用倒序列舉,具體實現步驟見**。

#include#include#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define n 1010// 如果正向建立並查集,正向刪除,那麼每一次都需要維護重置並查集。//所以我們可以倒過來思考,從n到1列舉,//每次把i點加入圖中,也就是刪除1~k-1條邊,剩餘k~n,若最大集合點數不超過n/2,說明這種方案可行,且k還能小,//一旦不滿足,意味這k不能加入圖中,即k即為最小刪除邊。int fa[n],a[n][n],c[n];

//fa[i]表示i所在集合的根,c[i]表示i所在集合的總個數int find(int x)

return x==fa[x]?x:fa[x]=find(fa[x]);

int main()

int n;

scanf("%d",&n);

for(int i=1;i<=n;i++) //初始化{

fa[i]=i;

c[i]=1;

for(int i=1;i<=n;i++)

scanf("%d",&a[i][0]);

for(int j=1;j<=a[i][0];j++)

scanf("%d",&a[i][j]);

for(int i=n;i>=1;i--) //倒著列舉{

for(int j=1;j<=a[i][0];j++)

if(a[i][j]>i)

//因為是按順序刪除,這裡假設i點在圖中,所以接下來合併的點必須比i大,{

int r1=find(i),r2=find(a[i][j]);

if(r1!=r2)

fa[r2]=r1;//這裡是把i加入到圖中c[r1]+=c[r2];

if(c[i]>(n>>1))

//集合點數超過n/2,k不能進入圖中,必須刪k{

cout<

return 0;

return 0;

團夥 並查集 團夥 並查集

題目描述 1920年的芝加哥,出現了一群強盜。如果兩個強盜遇上了,那麼他們要麼是朋友,要麼是敵人。而且有一點是肯定的,就是 我朋友的朋友是我的朋友 我敵人的敵人也是我的朋友。兩個強盜是同一團夥的條件是當且僅當他們是朋友。現在給你一些關於強盜們的資訊,問你最多有多少個強盜團夥。輸入輸出格式 輸入格式 ...

團夥 並查集 並查集 團夥

2 n 1000 1 m 5000 1 p q n 試題分析 這種問題我們一般有兩種解法 打標記 多個並查集 打標記這類方法會在銀河英雄傳說中看到 那麼多個並查集如何解決呢?我們設1 n節點是記錄朋友,n 1 2 n節點是記錄敵人 既然兩個人是朋友,根據題意,我們也要把他們的敵人合起來 如果兩個人是...

團夥 並查集

problem description 在某城市裡住著n個人,任何兩個認識的人不是朋友就是敵人,而且滿足 1 我朋友的朋友是我的朋友 2 我敵人的敵人是我的朋友。所有是朋友的人組成乙個團夥。告訴你關於這n個人的m條資訊,即某兩個人是朋友,或者某兩個人是敵人,請你編寫乙個程式,計算出這個城市最多可能有...