给定一张二维高度地图, 你能够在第一行的格子里建水库。 如果两个相邻格子高度差大于 \(1\), 那么水能够从高的流去低的
如今问可否使最后一行的每一个格子里都有水, 如果能输出 \(1\) ,再输出最少建水库数; 如果不能输出不能的格子数ios
错误日志: 思路错了
调试日志: 区间覆盖未转换为闭区间spa
(反思)刚开始想从最后一行倒着搜上去, 用 \(bitset\) 维护一个01序列表示每一个格子至少须要在第一行建哪些水库之一
过样例交了一发 \(40\)分。
而后发现这个东西不是单单取并就行了啊。。处理完以后是个 \(k-SAT\) 无多项式解的。。3d
而后想正解
有无解很好判断, 搜索一下就出来了, 不可行答案直接统计便可
讨论有解的状况
首先对于第一行的每一个水库 \(x_{i}\) , 他能覆盖的最后一行必然是一个连续的区间
画图很好证实的
反证法:
假设存在一种状况使得覆盖状况以下:
假设蓝色覆盖路线以下:
由于右边红色被覆盖了, 因此从红色水库到下方必然有一条路径
发现路径必有交(紫色部分), 因此红色水库的水也会流入蓝色那部分, 假设不成立
故一座水库能覆盖的最后一行必然是一个连续的区间
证毕。调试
而后搜索一下第一行的每一个格子能到达的区间
作区间最少线段覆盖便可日志
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<algorithm> #include<climits> #define LL long long #define REP(i, x, y) for(int i = (x);i <= (y);i++) using namespace std; int RD(){ int out = 0,flag = 1;char c = getchar(); while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();} while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();} return flag * out; } const int maxn = 1019; int lenx, leny; int map[maxn][maxn]; bool vis[maxn][maxn]; int l[maxn][maxn], r[maxn][maxn]; int mx[4] = {0, 0,-1, 1}; int my[4] = {1,-1, 0, 0}; bool judge(int x, int y){return !(x < 1 || x > lenx || y < 1 || y > leny);} void dfs(int x, int y){ vis[x][y] = 1;//记忆化+到达标记 REP(k, 0, 3){ int nx = x + mx[k], ny = y + my[k]; if(!judge(nx, ny) || map[nx][ny] >= map[x][y])continue; if(!vis[nx][ny])dfs(nx, ny); l[x][y] = min(l[x][y], l[nx][ny]); r[x][y] = max(r[x][y], r[nx][ny]); } } struct Node{int l, r;}I[maxn]; int cnt; int main(){ lenx = RD(), leny = RD(); REP(i, 1, lenx)REP(j, 1, leny)map[i][j] = RD(); memset(l, 127, sizeof(l));//r初始为0就得 REP(i, 1, leny)l[lenx][i] = r[lenx][i] = i; REP(i, 1, leny)dfs(1, i); int flag = 0; REP(i, 1, leny){ if(!vis[lenx][i])flag++; if(r[1][i])I[++cnt] = (Node){l[1][i] - 1, r[1][i]};//记录合法线段(记得转换为区间相交) } if(flag){printf("0\n%d\n", flag);return 0;} int ans = 0, now = 0, next = 0; REP(i, 1, cnt){ if(I[i].l <= now)next = max(next, I[i].r); else{ ans++, now = next; if(I[i].l > now);//已经判断必定有解了 next = max(next, I[i].r); } } puts("1"); if(now < leny)printf("%d\n", ans + 1); else printf("%d\n", ans); return 0; }