专栏文章
P1514 [NOIP 2010 提高组] 引水入城题解
P1514题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipmmo80
- 此快照首次捕获于
- 2025/12/03 14:29 3 个月前
- 此快照最后确认于
- 2025/12/03 14:29 3 个月前
题目大意
一个国家可以看做是一个 的矩阵,每一个格子就是一个城市。现在要在第 行的城市中建蓄水厂,将水输送到第 行的每一个城市。水只能从海拔高的地方流向海拔低的地方。求最少要建造几个蓄水厂。
思路分析
对于每一个在第 行的城市,采用广度优先搜索,搜索如果在这里建蓄水厂,水能流向哪几个在第 行的城市,用标记数组记录。如果有在第 行的城市没办法收到水,则输出 和缺水城市的数量。
但是如果每一座城市都能收到水,至少该建几个蓄水厂呢?
定理
在有解的情况下,每个蓄水厂流到的第 行城市是个区间。
证明

假设图上绿色的城市建造蓄水厂,水从蓝色的路线流向最后一行的黄色城市。其中橙色城市没有收到水。此时,第 行城市中覆盖的范围不是个区间。

因为要保证题目一定有解,所以一定有第 行的一座城市能给橙色城市供水。图中红色城市能给橙色城市供水。

此时,绿色城市的供水路线与红色城市的供水路线存在着重叠,即图中深蓝色路线。而显然地,既然红色城市供的水能从深蓝色路线流向橙色城市,那么绿色城市供的水也可以。

因此,每个蓄水厂流到的第 行城市是个区间。
证毕。
既然每个蓄水厂流到的第 行城市是个区间,接下来就可以使用线段覆盖的方法解题。下文把 座城市看做一条长度为 的线段,每个蓄水厂流向的区间看做是一条条线段。
思路很简单,采用贪心,先设一个变量记录最大左端点,遍历每条线段的左端点与右端点。在左端点小于等于最大左端点的线段中选择右端点最大的一条线段,将最大左端点更新为这条线段的右端点,以此往复,直到最大左端点大于等于 即可。最后输出的线段数即为答案。
AC 代码
CPP#include <bits/stdc++.h>
using namespace std;
struct city{ //蓄水厂,有水流向沙漠城市的左端点和右端点
int st,en;
}cities[510];
int n,m,s[510][510],L=1,ans=0;
int dh[5]={0,-1,0,1,0};
int dl[5]={0,0,1,0,-1};
bool f[510][510][510],p[510];
void bfs(int r,int c,int j){ //广搜,搜索水能流向那几座城市
queue<int> qx,qy;
qx.push(r);
qy.push(c);
f[j][r][c]=true;
if(n==1){
p[c]=true;
}
while(!qx.empty()){
int x=qx.front(),y=qy.front();
qx.pop();
qy.pop();
for(int i=1;i<=4;i++){
int dx=x+dh[i],dy=y+dl[i];
if(dx>=1 && dx<=n && dy>=1 && dy<=m){
if(!f[j][dx][dy] && s[dx][dy]<s[x][y]){
f[j][dx][dy]=true;
qx.push(dx);
qy.push(dy);
if(dx==n){
p[dy]=true; //标记数组,记录是不是每座沙漠城市都有水
cities[j].st=min(cities[j].st,dy); //因为一定是一个区间,所以直接统计左右端点
cities[j].en=max(cities[j].en,dy);
}
}
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>s[i][j];
}
}
for(int i=1;i<=m;i++){
cities[i].st=i;
cities[i].en=i;
}
for(int i=1;i<=m;i++){
bfs(1,i,i);
}
int city_num=0;
for(int i=1;i<=m;i++){
if(!p[i]){
city_num++;
}
}
if(city_num){ //有沙漠城市没有水
cout<<"0\n"<<city_num;
return 0;
}
cout<<"1\n";
while(L<=m){ //线段覆盖
int maxa=-1,maxn=-1e9;
for(int i=1;i<=m;i++){
if(cities[i].st<=L){
if(cities[i].en>maxn){
maxa=i;
maxn=cities[i].en;
}
}
}
L=cities[maxa].en+1;
ans++;
}
cout<<ans; //输出答案
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...