1. 程式人生 > 實用技巧 >【題解】[USACO13FEB]Tractor S

【題解】[USACO13FEB]Tractor S

題目戳我

\(\text{Solution:}\)

好久沒寫啥\(dfs\)了,借這個題整理下細節。

觀察到答案具有二分性,所以先求出其差的最大最小值,\(\log val\)的複雜度不成問題。

考慮如何\(check:\)

考慮一個\(dfs\)預處理當前點為\((i,j),\)高度為\(k\)所能到達的所有點。這一步是\(n^2\)的複雜度。注意判斷是否出界的時候符號不要打反,以及這題所謂高度差是在絕對值意義上的。

遍歷變數時不要重名。

於是,這題可以在\(O(n^2\log m)\)的複雜度完成。

還有一個想法是求出原樹的最小生成樹後處理出\(siz\)和子樹的最大差。然後可以\((n^2\log n^2)\)

實現這題。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+10;
int a[501][501],n;
const int dx[4]={1,0,-1,0};
const int dy[4]={0,1,0,-1};
int L,R,ans,vis[501][501];
int dfs(int x,int y,int kk){
	int cnt=1;
	vis[x][y]=1;
	for(int k=0;k<4;++k){
		int nx=x+dx[k],ny=y+dy[k];
		if(nx<1||ny<1||nx>n||ny>n||vis[nx][ny]||abs(a[x][y]-a[nx][ny])>kk)continue;
		cnt+=dfs(nx,ny,kk);
	}
	return cnt;
}
bool check(int k){
	memset(vis,0,sizeof vis);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){
			if(vis[i][j])continue;
			int C=dfs(i,j,k);
			if(C*2>=n*n)return true;
		}
	return false;
}
int main(){
	scanf("%d",&n);
	L=(1<<30);R=-L;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%d",&a[i][j]);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			for(int k=0;k<4;++k){
				int x=i+dx[k],y=j+dy[k];
				R=max(R,a[i][j]-a[x][y]);
				L=min(L,a[i][j]-a[x][y]);
			}
		}
	}
	while(L<=R){
		int mid=L+R>>1;
		if(check(mid))ans=mid,R=mid-1;
		else L=mid+1; 
	}
	printf("%d\n",ans);
	return 0;
}