思路:首先用BFS搜索(其实用记忆化的DFS更好)能够到达的城市,判断一下是否所有城市都能够被覆盖即可完成第一问,那么关键在于第二问怎么完成,通过思考可以得出"如果每座城市都可以到达,那么一个蓄水场可到达的城市是连续的"这样一个结论,那么就变成了一个区间覆盖问题,至此已经可以完成这一题了
/**
* 洛谷oj: P1514 引水入城
* 类型:搜索,贪心
*/
#include<algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
struct City {
int l, r;
bool operator < (City a) const {
return l < a.l;
}
};
struct Pos {
int x, y;
};
const int maxn = 500+10;
const int dx[] = {0,0,1,-1};
const int dy[] = {1,-1,0,0};
bool vis[maxn][maxn], isget[maxn], used[maxn];
int maps[maxn][maxn];
int n, m;
vector<City> citys;
void bfs(int a) {
int l = 0x3f3f3f3f, r = -0x3f3f3f3f;
bool iscan = 0;
queue<Pos> que;
que.push(Pos{1,a});
vis[1][a] = 1;
if( n == 1 ) { //当这个城市即是沿海城市又是沙漠城市时的特判
iscan = 1;
isget[a] = 1;
l = min(l, a);
r = max(r, a);
}
while(!que.empty()) {
Pos cur = que.front(); que.pop();
if( cur.x == 1 ) used[cur.y] = 1;
for(int i = 0; i < 4; i++) {
int tx = cur.x + dx[i], ty = cur.y + dy[i];
if(!vis[tx][ty] && ( tx >= 1 && tx <= n && ty >= 1 && ty <= m ) && maps[tx][ty] < maps[cur.x][cur.y] ) {
vis[tx][ty] = 1;
que.push(Pos{tx,ty});
if( tx == n ) {
iscan = 1;
isget[ty] = 1;
l = min(l, ty);
r = max(r, ty);
}
}
}
}
if(iscan) citys.push_back(City{l,r});
memset(vis, 0, sizeof(vis));
}
int main() {
/************input***********/
memset(maps, -0x3f, sizeof(maps));
scanf("%d %d", &n, &m);
for( int i = 1; i <= n; i++ )
for( int j = 1; j <= m; j++ )
scanf("%d", &maps[i][j]);
/****************************/
//bfs跑图
for( int i = 1; i <= m; i++ )
if( maps[1][i] >= maps[1][i-1] && maps[1][i] >= maps[1][i+1] ) //如果其海拔小于边上的蓄水池那么该蓄水池是无意义的
bfs(i);
int ans1 = 1, ans2 = 0;
for( int i = 1; i <= m; i++ ) {
if( !isget[i] ) {
ans1 = 0;
ans2++;
}
}
printf("%d\n", ans1);
if(!ans1) {
printf("%d\n", ans2);
return 0;
}
//排序
sort(citys.begin(), citys.end());
//跑一遍贪心区间覆盖模板
int last = 1, i = 0;
while( last <= m ) {
int t = 0;
while(citys[i].l <= last) t = max(citys[i++].r, t);
last = t + 1; ans2++;
}
printf("%d\n", ans2);
return 0;
}