题解:
最开始的思路是全排列+搜索,预估30分。正解是搜索+DP,先对每个
靠近河岸的点搜一次,保存下来这个点能够覆盖的区间,也就是能到达
的靠近沙漠的点,然后对于这些区间进行DP,找出覆盖所有区间用的
最少的点。另外用一个数组保存所有蓄水站能够覆盖到的点,来找到不能覆盖完的情况。
搜索部分是常规的DFS,DP部分定义d(i),表示覆盖到i点的一个状态,遍历j来寻找最优的重叠情况。
代码:
#include<bits/stdc++.h>
#define MAXA 700
using namespace std;
bool vis[MAXA][MAXA];
int n,m,cnt,OK[MAXA],Map[MAXA][MAXA],d[MAXA],Left[MAXA],Right[MAXA];
int drct[5][3] = {{1,0},{-1,0},{0,1},{0,-1}};
void DFS(int x,int y,int origin) {
if(x == n) {
OK[y] = 1;
Left[origin] = min(Left[origin],y);
Right[origin] = max(Right[origin],y);
}
for(int i=0;i<=3;i++) {
int tx = x + drct[i][0];
int ty = y + drct[i][1];
if(!vis[tx][ty] && Map[tx][ty] < Map[x][y] && tx >= 1 && tx <= n && ty >= 1 && ty <= m) {
vis[tx][ty] = 1;
DFS(tx,ty,origin);
//vis[tx][ty] = 0;
}
}
}
int main() {
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&Map[i][j]);
for(int i=0;i<=MAXA;i++)
Left[i] = d[i] = 0x3f3f3f3f;
for(int i=1;i<=m;i++) {
if(Map[1][i-1] <= Map[1][i] && Map[1][i] >= Map[1][i+1])
DFS(1,i,i);
memset(vis,0,sizeof(vis));
}
for(int i=1;i<=m;i++)
if(!OK[i])
cnt++;
if(cnt) {
printf("0\n");
printf("%d",cnt);
return 0;
}
d[0] = 0;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++) {
if(Left[j] <= i && i <= Right[j])
d[i] = min(d[i],d[Left[j]-1]+1);
}
printf("1\n");
printf("%d",d[m]);
}