P1514 引水入城


P1514 引水入城

給定一張二維高度地圖, 你可以在第一行的格子里建水庫。 若是兩個相鄰格子高度差大於 \(1\), 那么水可以從高的流去低的
現在問能否使最后一行的每個格子里都有水, 若是能輸出 \(1\) ,再輸出最少建水庫數; 若是不能輸出不能的格子數


錯誤日志: 思路錯了
調試日志: 區間覆蓋未轉換為閉區間


Solution

(反思)剛開始想從最后一行倒着搜上去, 用 \(bitset\) 維護一個01序列表示每個格子至少需要在第一行建哪些水庫之一
過樣例交了一發 \(40\)分。
然后發現這個東西不是單單取並就好了啊。。處理完之后是個 \(k-SAT\) 無多項式解的。。

然后想正解
有無解很好判斷, 搜索一下就出來了, 不可行答案直接統計即可
討論有解的情況
首先對於第一行的每個水庫 \(x_{i}\) , 他能覆蓋的最后一行必然是一個連續的區間
畫圖很好證明的
反證法:
假設存在一種情況使得覆蓋情況如下:

假設藍色覆蓋路線如下:

因為右邊紅色被覆蓋了, 所以從紅色水庫到下方必然有一條路徑

發現路徑必有交(紫色部分), 所以紅色水庫的水也會流入藍色那部分, 假設不成立
故一座水庫能覆蓋的最后一行必然是一個連續的區間
證畢。

然后搜索一下第一行的每個格子能到達的區間
做區間最少線段覆蓋即可

Code

#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;
	}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM