题目链接:https://www.luogu.org/problemnew/show/P1514
题意理解
第一排可以建蓄水厂和输水站。其他排只能建输水站。最后一排必须每座城市都建一个输水站。
对于不能满足的情况,我们可以考虑在第一排建满蓄水站,然后数一下最后一排有多少个没有水利设施的。我选择使用dfs,应该也可以用bfs。
对于能满足的情况,如果使用全排列做,复杂度会炸。然后观察可以发现,其实第一排每个搞出来的最后一排的城市,应该是连续的。于是变成了线段的全覆盖问题。这时候可以用dp去做。
考虑到数据量这么小,基本可以考虑不要优化常数。。。
代码
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 600;
int N, M;
int a[maxn][maxn];
bool visited[maxn][maxn];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
typedef struct {
int s;
int e;
} F;
F f[maxn];
int dp[maxn];
void dfs(int x, int y) {
if (x < 1 || x > N || y < 1 || y > M) {
return;
}
if (visited[x][y]) {
return;
}
visited[x][y] = true;
for (int i = 0; i < 4; i++) {
int tx = x + dx[i];
int ty = y + dy[i];
if (tx < 1 || tx > N || ty < 1 || ty > M) {
continue;
}
if (a[x][y] > a[tx][ty]) {
dfs(tx, ty);
}
}
}
int cmp(F f1, F f2) {
return f1.s < f2.s;
}
int main() {
scanf("%d", &N);
scanf("%d", &M);
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
scanf("%d", &a[i][j]);
}
}
for (int i = 1; i <= M; i++) {
dfs(1, i);
}
int not_ok = 0;
for (int i = 1; i <= M; i++) {
if (!visited[N][i]) {
not_ok++;
}
}
if (not_ok) {
printf("0\n");
printf("%d\n", not_ok);
return 0;
}
printf("1\n");
memset(visited, 0, sizeof visited);
for (int i = 1; i <= M; i++) {
dfs(1, i);
f[i].s = M + 1;
f[i].e = 0;
for (int j = 1; j <= M; j++) {
if (visited[N][j]) {
f[i].s = f[i].s < j ? f[i].s : j;
f[i].e = f[i].e > j ? f[i].e : j;
}
}
memset(visited, 0, sizeof visited);
}
dp[0] = 0;
sort(f + 1, f + 1 + M, cmp);
int now = 0;
int to = 0;
int ans = 0;
for(int i = 1; i <= M; i++) {
if(f[i].s > now + 1) {
ans++;
now = to;
to = max(to, f[i].e);
} else {
to = max(to, f[i].e);
}
}
if(now != M) {
ans++;
}
printf("%d", ans);
return 0;
}