1. 程式人生 > 其它 >NOI科目校 資訊學知識點測評-圖論專題【51nod】 遊記

NOI科目校 資訊學知識點測評-圖論專題【51nod】 遊記

比賽地址:Link

A 顏色塊

1.0 秒 131,072.0 KB 100 分
一張 \(m\times n\) 的圖片,每個點有一個顏色,相同顏色的點連在一起(上下左右四連通)屬於同一個顏色塊,問這張圖片共有多少個顏色塊。資料保證單個顏色塊的點數量不超過 \(10^5\)

輸入

第一行:2個數\(n\)\(m\),中間用空格分隔,表示地圖的大小(\(1 <= m, n <= 1000\))。
後面\(n\)行:每行\(m\)個字元,對應圖片中的點的顏色編號\(c\)。(\(0 <= c <= 9\))。

輸出

輸出一個數,對應顏色塊的數量

資料範圍

\(1 <= m, n <= 1000\)

輸入樣例

5 5
11122
33112
31113
22113
21111

輸出樣例

5

樣例解釋

整個圖中,有1個顏色為1的色塊,2個顏色為2的色塊,2個顏色為3的色塊,因此共有5個色塊。

通過記錄

唰唰唰!秒殺!
毫無任何問題。

程式碼

#include<bits/stdc++.h>
using namespace std;
int mp[1005][1005];//存地圖
bool v[1005][1005];//visited
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//四個方向
int m,n,ans=0;//ans=顏色塊個數
void dfs(int x,int y){
	v[x][y]=1;//設定為標記過
	for(int i=0;i<4;i++){
		int dx=dir[i][0]+x,dy=dir[i][1]+y;
		if(dx>=1&&dx<=n&&dy>=1&&dy<=m&&!v[dx][dy]&&mp[dx][dy]==mp[x][y]) dfs(dx,dy);//符合條件
	}
}
int main(){
	char c;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>c;
			mp[i][j]=c-'0';//過於緊湊
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!v[i][j]){//每個都找一遍
				dfs(i,j);
				ans++;
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

B 冬奧會之積水問題

3.0 秒 131,072.0 KB 100 分
冬奧會賽場旁有一片正方形的窪地(長寬都為\(n\)),地形凹凸不平,窪地的四周是一圈排水池。有一天,下了很大的雨,窪地形成了積水,告訴你窪地的地形(\(n\times n\)塊的高度),由你來計算,窪地的積水量。

例如:\(n = 4\)

3 4 5 6
4 1 2 7
5 1 2 8
6 7 8 9

因為四周都是排水池(邊界上的水會通過排水池流走),最終只有橘色部分(內圈):

1 2
1 2

能夠形成積水,積水高度由他們4周(綠色部分,外圈)的最低高度決定,這個高度是4(左上角0,0位置的3雖然小於4,但2個高度為4的方塊已經形成了封閉的一圈),所以總的積水量是10。

輸入

第一行:一個數n,表示窪地的大小(\(3 <= n <= 1000\))
後面n行:每行n個數,表示地形的高度h[i,j](\(0 <= h[i,j] <= 1000000\))。

輸出

輸出總的積水量。

輸入樣例

4
3 4 5 6
4 1 2 7
5 1 2 8
6 7 8 9

輸出樣例

10

思路

floodfill。
模擬海平面,每次增高都嘗試流一遍。

悲慘de做題過程

最開始寫了一發,慘拿46TAT
結果發現數組開小了/kx
然後卡在91卡了0.5h,終於發現寫的時候沒有處理0,順序反了/kx
然後就100了/cy
這告訴了我們:一定要搞清楚you在幹什麼!!!!!

code

#include<bits/stdc++.h>
using namespace std;
#define int long long
int mp[1005][1005];//地圖
char vis[1005][1005];//是的,其實沒啥用
struct three{
	int gao,x,y;//gao是高度
	bool operator <(three b) const{
		return gao>b.gao;
	}
};
priority_queue<three> q;
int n,m,mx=-1;
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
signed main(){
	cin>>n;
	m=n;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){cin>>mp[i][j];mx=max(mx,mp[i][j]);}//mx存最大值
	for(int i=1;i<=m;i++){//處理四周
		q.push({mp[1][i],1,i});
		q.push({mp[n][i],n,i});
		vis[1][i]=2;
		vis[n][i]=2;
	}
	for(int i=1;i<=n;i++){
		q.push({mp[i][1],i,1});
		q.push({mp[i][m],i,m});
		vis[i][1]=2;
		vis[i][m]=2;
	}
	int ans=0,hpm=0;//hpm=海平面
	three now;
	while(!q.empty()&&hpm<=mx){
	//cout<<q.top().gao<<' '<<hpm<<endl;
		now=q.top();
		while(!q.empty()&&now.gao<=hpm){
			if(vis[now.x][now.y]==1){//這地方被淹了
				ans+=hpm-now.gao;
				//cout<<now.x<<","<<now.y<<":"<<now.gao<<" "<<hpm<<endl;
			}
			q.pop();
			vis[now.x][now.y]=2;
			for(int i=0;i<4;i++){
				int dx=now.x+dir[i][0];
				int dy=now.y+dir[i][1];
				if(dx>=1&&dx<=n&&dy>=1&&dy<=m&&!vis[dx][dy]){//檢視四周
					vis[dx][dy]=1;
					q.push({mp[dx][dy],dx,dy});
				}
			}
			now=q.top();
		}
		hpm++;
	}
	cout<<ans<<endl;
	return 0;
}
/*以下是自造測試資料
4
0 2 100 0
10000 1 1 233
114 1 1 514
0 123 456 0
10
0 0 0 0 1 1 1 0 0 0
0 0 1 1 0 0 0 1 0 0
0 1 0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 1 1 1 0 0 0
*/

(C沒做出來不放了)

D 黏菌網路

1.0 秒 131,072.0 KB 100 分
小明正在研究黏菌(slime molds)。他有一張網狀格柵,共\(10\times10\)個交點,每個交點上可以放置一些物體。他選擇了其中3個交點,分別放置黏菌(M),糖(S),以及一塊有毒物質(P),如下所示:

..........
..........
..........
..S.......
..........
.....P....
..........
..........
.....M....
..........

之後觀察黏菌是否能避開毒物,並沿網格以最短路線找到糖。

小明希望你先幫忙算出黏菌到達糖之前至少要經過多少個空交點,以便他做實驗記錄。

輸入

輸入共10行,每行一個長度為10的字串描述\(10\times10\)格柵中交點的情況。其中'.'表示空交點,'M'表示放置了黏菌,'S'表示放置了糖,'P'表示放置了毒物。保證輸入資料中僅存在一組'M','S','P'。

輸出

輸出一個整數,表示黏菌經過的空交點的最小數量。

輸入樣例

..........
..........
..........
..S.......
..........
.....P....
..........
..........
.....M....
..........

輸出樣例

7

樣例解釋

..........
..........
..........
..S.......
..7.......
..6..P....
..5.......
..4.......
..321M....
..........

如上所示,黏菌需要經過至少7個空交點。

思路

這題放在T4也是絕了,是四道題裡最簡單的。
一個障礙,\(10\times 10\)大小,也不過如此。
直接爆搜。

通過記錄

直接寫。

code

#include<bits/stdc++.h>
using namespace std;
int n=10,sx,sy,ex,ey,ans=0;//startx,starty,endx,endy
bool mp[15][15];//map
bool v[15][15];//visited
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct th{//three
	int x,y,stp;
}now;
queue<th> q;
int bfs(){//bfs
	q.push({sx,sy,0});
	v[sx][sy]=1;
	while(!q.empty()){
		now=q.front();
		if(now.x==ex&&now.y==ey) return now.stp-1;//end
		q.pop();
		for(int i=0;i<4;i++){
			int dx=dir[i][0]+now.x,dy=dir[i][1]+now.y;
			if(dx>=1&&dx<=n&&dy>=1&&dy<=n&&!mp[dx][dy]&&!v[dx][dy]){//ok
				v[dx][dy]=1;
				q.push({dx,dy,now.stp+1});
			} 
		}
	}
	return -1;
}
int main(){
	char c;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			cin>>c;
			if(c=='M') sx=i,sy=j;//m
			else if(c=='S') ex=i,ey=j;//s
			else if(c=='P') mp[i][j]=1;//p
		}
	cout<<bfs()<<endl;
	return 0;
}