--- title: "农田灌溉" created: 2025-11-28 tags: - 算法 --- # 农田灌溉 ## 题目 [农田灌溉](https://www.acwing.com/problem/content/description/4380/) ![[image-b1a5605e.png]] ## 思路分析 二分去找答案 假设x秒刚好完成所有农田的灌溉 那大于x秒就都可以把农田灌溉完成 小于这个x就不能 所以应该是个最小答案 区间划分成左半边不满足 右半边满足 即r=mid l=mid+1 主要是如何判断在经过mid秒后 农田是否全部灌溉 那就用mid去代入 同时洒水即遍历k个有洒水器的农田 因为每经过一秒向左右拓展一个农田 其实第一秒只会灌溉当前农田 不会拓展 也就是说 mid秒的话 只会向左向右拓展mid-1块农田 那假设有洒水器的农田为p[i] 则这个洒水器在mid秒能灌溉的农田为p[i]-(m-1)到p[i]+(m-1) 让j去表示它 在它的范围内j++ 但是有个条件是j存在 在1~n的范围内 如果满足 就使用s[j]记录当前农田被灌溉过了 最后检查一遍 遍历s数组 看是否全被灌溉过了 如果满足 就说明当前的mid时间是可以灌溉所有农田的 在答案的右边或者刚好在答案上 ## 代码实现 **二分+暴力枚举检查** ```cpp #include using namespace std; #define endl '\n' const int N=210; int p[N],s[N]; int T,n,k; bool check(int m){ memset(s,0,sizeof s); for(int i=1;i<=k;i++) for(int j=p[i]-(m-1);j<=p[i]+(m-1);j++) if(j>=1 && j<=n) s[j]=1; for(int i=1;i<=n;i++) if(s[i]==0) return false; return true; } int main() { ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>T; while(T--){ cin>>n>>k; for(int i=1;i<=k;i++) cin>>p[i]; int l=1,r=n; while(l>1; if(check(mid)) r=mid; else l=mid+1; } cout< using namespace std; #define endl '\n' typedef pair PII; const int N=210; int p[N]; int T,n,k; bool check(int m){ vector segs; for(int i=1;i<=k;i++){ int left=max(1,p[i]-(m-1)),right=min(n,p[i]+(m-1)); segs.push_back({left,right}); } sort(segs.begin(),segs.end()); if(segs.empty() || segs[0].first>1) return false; int covered=segs[0].second; for(int i=1;icovered+1) return false; covered=max(covered,segs[i].second); } return covered==n; } int main() { ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>T; while(T--){ cin>>n>>k; for(int i=1;i<=k;i++) cin>>p[i]; int l=1,r=n; while(l>1; if(check(mid)) r=mid; else l=mid+1; } cout<