1. 程式人生 > >Luogu P1514 引水入城

Luogu P1514 引水入城

using 格子 () mat 通過 queue 一行 code 城市

題目描述

在一個遙遠的國度,一側是風景秀美的湖泊,另一側則是漫無邊際的沙漠。該國的行政區劃十分特殊,剛好構成一個 \(N\)\(\times M\) 列的矩形,如上圖所示,其中每個格子都代表一座城市,每座城市都有一個海拔高度。

技術分享圖片

為了使居民們都盡可能飲用到清澈的湖水,現在要在某些城市建造水利設施。水利設施有兩種,分別為蓄水廠和輸水站。蓄水廠的功能是利用水泵將湖泊中的水抽取到所在城市的蓄水池中。

因此,只有與湖泊毗鄰的第\(1\)行的城市可以建造蓄水廠。而輸水站的功能則是通過輸水管線利用高度落差,將湖水從高處向低處輸送。故一座城市能建造輸水站的前提,是存在比它海拔更高且擁有公共邊的相鄰城市,已經建有水利設施。由於第 \(N\)

行的城市靠近沙漠,是該國的幹旱區,所以要求其中的每座城市都建有水利設施。那麽,這個要求能否滿足呢?如果能,請計算最少建造幾個蓄水廠;如果不能,求幹旱區中不可能建有水利設施的城市數目。

輸入樣例#1

2 5
9 1 5 4 3
8 7 6 1 2

輸出樣例#1

1
1

輸入樣例#2

3 6
8 4 5 6 4 4
7 3 4 3 3 3
3 2 2 1 1 2

輸出樣例#2

1
3

說明

【樣例1 說明】

只需要在海拔為 99 的那座城市中建造蓄水廠,即可滿足要求。

【樣例2 說明】

技術分享圖片

上圖中,在 3 3 個粗線框出的城市中建造蓄水廠,可以滿足要求。以這 3 3 個蓄水廠為源頭在幹旱區中建造的輸水站分別用3 種顏色標出。當然,建造方法可能不唯一。

數據範圍

技術分享圖片

思路

乍一看貌似只能打暴力,於是不顧一切的開始淦
但是結果很感人啊
技術分享圖片

後來想起來,之前學姐講過這個題。
但是當時並沒有好好聽課,so還是不會,我就開始想啊
好像是要用貪心來啊
但是咋貪是個問題
於是我繼續看題目
最下面的圖片讓我記起來了咋做


我們先用一個普通的\(DFS\)來判斷第\(N\)行的所有點能否引水入城在確定能夠滿足題目要求之後
我們來想一下。這樣的一張滿足要求的圖,第一行的每一個點的水所能流到的最後一行的點必然是一個區間
為什麽?

我可以告訴你我不知道啦啦啦啦

那麽將第一行每一個點能夠放水的城市就可以用BFS變成了一個區間,然後做一個區間覆蓋就能得出答案了

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>

const int maxn = 503;

using namespace std;

int n, m, h[maxn][maxn], nownode, Ans, tot;
bool vis[maxn][maxn], book[maxn], hhh;
int dx[6] = {1, 0, -1, 0};
int dy[6] = {0, 1, 0, -1};

struct edge {
    int l, r;
}ed[maxn];
struct node {
    int x, y;
};

queue<node> Q;

bool cmp(edge a, edge b) {
    if(a.l != b.l) return a.l < b.l;
    return a.r > b.r;
}

void BFS(node now) {
    while(!Q.empty()) {
        now = Q.front();
        Q.pop();
        int x = now.x, y = now.y;
        if(x == n) {
            ed[nownode].l = min(ed[nownode].l, y);
            ed[nownode].r = max(ed[nownode].r, y);
        }
        for(int i=0; i<4; i++) {
            int xx = dx[i]+x, yy = dy[i]+y;
            if(!vis[xx][yy] && xx <= n && xx > 0 && yy <= m && yy > 0 && h[xx][yy] < h[x][y]) {
                Q.push((node) {xx, yy});
                vis[xx][yy] = 1;
            }
        }
    }
}

void dfs(int x, int y) {
    if(x == n) {
        ++tot;
    }
    for(int i=0; i<4; i++) {
        int xx = dx[i]+x, yy = dy[i]+y;
        if(h[xx][yy] < h[x][y] && !vis[xx][yy] && xx > 0 && yy > 0 && xx <= n && yy <= m) {
            vis[xx][yy] = 1;
            dfs(xx, yy);
        }
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=m; j++) {
            scanf("%d", &h[i][j]);
        }
    }
    for(int i=1; i<=m; i++) {
        dfs(1, i);
    }
    if(tot < m) {
        printf("0\n%d", m-tot);
        return 0;
    }
    for(int i=1; i<=m; i++) {
        nownode = i;
        ed[nownode].l = 2147483647;
        ed[nownode].r = 0;
        while (!Q.empty()) Q.pop();
        memset(vis, 0, sizeof(vis));
        vis[1][i] = 1;
        Q.push((node) {1, i});
        BFS(Q.front());
    }
    sort(ed+1, ed+1+m, cmp);
    int cur = 0, nur = 0;
    Ans = 0;
    for(int i=1; i<=m; i++) {
        if(ed[i].l > m) break;
        if(ed[i].l <= cur+1)
            nur = max(ed[i].r, nur);
        else {
            cur = nur;
            Ans++;
            nur = max(nur, ed[i].r);
        }
    }
    if(cur != m) Ans++;
    printf("1\n%d", Ans);
    return 0;
}

Luogu P1514 引水入城