[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條資訊,即某兩個人是朋友,或者某兩個人是敵人,請你編寫乙個程式,計算出這個城市最多可能有...