题解:P1514 [NOIP2010 提高组] 引水入城
P1514 [NOIP2010 提高组] 引水入城题解
简要题意
在第
特殊性分析
证明如果满足第
在下图的第
而因为在满足第
所以蓝色经过的路线就可以在蓝色与红色的交点处转弯,走红色的部分到达(如下图)。
所以猜想成立
思路
将每个蓄水厂所能覆盖到第
因为我们需要最小化蓄水厂的数量,所以考虑贪心。
贪心方案:
对于在第
正确性证明:
如果已经可以收到确定建造的蓄水厂的水了,如果这时再建新的蓄水厂,这时的答案肯定更劣。
对于建造从它开始覆盖长度最长的那个蓄水厂的原因肯定就是显而易见的了。
code
如果你还是不明白,那就看下代码吧!
最终时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N=501;
vector<int> water[N];//在第 n 行第 i 列的城市有哪些在第 1 行蓄水厂的水可以到达。
//也就是在第 n 行第 i 列的城市能接收到水的蓄水厂编号的集合。
//例如 water[3]={1,2,4} 就表示在第 n 行第 3 列的城市能接收到在第 1 行第 1,2,4 列城市所建的蓄水厂的水
int mp[N][N],n,m,last[N];
bool vis[N][N],flag[N];
//flag[i] 表示第 1 行的第 i 列的城市是否确定要放蓄水厂
struct node{
int x,y,h;
};
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
queue<node> q;
void bfs(int x){
memset(vis,0,sizeof(vis));
q.push({1,x,mp[1][x]});
while(!q.empty()){
int nx=q.front().x,ny=q.front().y,nh=q.front().h;
q.pop();
if(vis[nx][ny]) continue;
vis[nx][ny]=1;
if(nx==n) water[ny].push_back(x);//如果流到第 n 行了就记录这个城市可以收到哪些蓄水厂的水
if(nx+1<=n && mp[nx+1][ny]<nh) q.push({nx+1,ny,mp[nx+1][ny]}); //bfs 模拟水流。
if(ny+1<=m && mp[nx][ny+1]<nh) q.push({nx,ny+1,mp[nx][ny+1]});
if(nx-1>=1 && mp[nx-1][ny]<nh) q.push({nx-1,ny,mp[nx-1][ny]});
if(ny-1>=1 && mp[nx][ny-1]<nh) q.push({nx,ny-1,mp[nx][ny-1]});
}
}
int main(){
cin>>n>>m;
int ans=0,op_ans=1,ans2=0;
for(register int i=1;i<=n;i++) for(int j=1;j<=m;j++) mp[i][j]=read();
for(register int i=1;i<=m;i++) bfs(i);//尝试在第 1 行的第 i 列的城市上放蓄水厂
for(register int i=1;i<=m;i++) if(!water[i].size()) op_ans=0,ans2++;//如果在第 n 行有城市不能收到水就无解
if(!op_ans){
cout<<0<<endl<<ans2;
return 0;
}
for(register int i=1;i<=m;i++) for(int j=0;j<water[i].size();j++)last[water[i][j]]=i;//记录最后一次出现来判断覆盖的区间是否最大
for(register int i=1;i<=m;i++){
bool flag2=0;
for(register int j=0;j<water[i].size();j++)if(flag[water[i][j]]==1){flag2=1;break;}//已经有确定建造的了。
if(flag2==0){//如果不包含确定建造的蓄水厂
ans++;
int max_last=0,maxj=0;
for(register int j=0;j<water[i].size();j++) if(last[water[i][j]]>max_last) max_last=last[water[i][j]],maxj=j;
flag[water[i][maxj]]=1;//选择覆盖的区间最大的蓄水厂来建。
}
}
cout<<1<<endl<<ans;
return 0;
}
码字不易,给个赞吧QwQ。