給定一張二維高度地圖, 你能夠在第一行的格子裏建水庫。 如果兩個相鄰格子高度差大於 \(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; }