洛谷 1514 引水入城(記憶化搜索+DP)

*PS:做的時候還以爲純搜索,後來發現竟然有DP??exm?調了好長時間,從此dp一生黑(假的)QwQ。

go to the problem

題目描述

在一個遙遠的國度,一側是風景秀美的湖泊,另一側則是漫無邊際的沙漠。該國的行政區劃十分特殊,剛好構成一個N 行M 列的矩形,如上圖所示,其中每個格子都代表一座城市,每座城市都有一個海拔高度。
這裏寫圖片描述
爲了使居民們都儘可能飲用到清澈的湖水,現在要在某些城市建造水利設施。水利設施有兩種,分別爲蓄水廠和輸水站。蓄水廠的功能是利用水泵將湖泊中的水抽取到所在城市的蓄水池中。

因此,只有與湖泊毗鄰的第1 行的城市可以建造蓄水廠。而輸水站的功能則是通過輸水管線利用高度落差,將湖水從高處向低處輸送。故一座城市能建造輸水站的前提,是存在比它海拔更高且擁有公共邊的相鄰城市,已經建有水利設施。由於第N 行的城市靠近沙漠,是該國的乾旱區,所以要求其中的每座城市都建有水利設施。那麼,這個要求能否滿足呢?如果能,請計算最少建造幾個蓄水廠;如果不能,求乾旱區中不可能建有水利設施的城市數目。

輸入輸出格式

輸入格式:
輸入文件的每行中兩個數之間用一個空格隔開。輸入的第一行是兩個正整數N 和M,表示矩形的規模。接下來N 行,每行M 個正整數,依次代表每座城市的海拔高度。

輸出格式:
輸出有兩行。如果能滿足要求,輸出的第一行是整數1,第二行是一個整數,代表最少建造幾個蓄水廠;如果不能滿足要求,輸出的第一行是整數0,第二行是一個整數,代表有幾座乾旱區中的城市不可能建有水利設施。

輸入輸出樣例

輸入樣例#1:
【輸入樣例1】
2 5
9 1 5 4 3
8 7 6 1 2

【輸入樣例2】
3 6
8 4 5 6 4 4
7 3 4 3 3 3
3 2 2 1 1 2
輸出樣例#1:
【輸出樣例1】
1
1

【輸出樣例2】
1
3

說明

【樣例1 說明】

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

【樣例2 說明】
這裏寫圖片描述
上圖中,在3 個粗線框出的城市中建造蓄水廠,可以滿足要求。以這3 個蓄水廠爲源頭

在乾旱區中建造的輸水站分別用3 種顏色標出。當然,建造方法可能不唯一。

【數據範圍】
這裏寫圖片描述

因爲水總是從高處向低處流,所以想到可以用搜索。
第一問很簡單,只需要一遍Bfs或Dfs就能解決。不能的情況也很簡單,只需要計算一下不能走到的有多少城市就行了。關鍵就是能的情況下如何計算最少建造幾個蓄水廠。
解決這個問題需要首先統計在第一行的每個城市修建一個蓄水廠在最後一行的城市水利設施所能遍及的範圍。
因爲第一行的城市最多有500個,城市總數最多有250000個,對每個城市都bfs一遍會超時,所以考慮記憶化搜索,對於每個城市處理他所能便利的區間,然後把區間合併,第一問可以在搜索中處理。
求最少建造的蓄水廠數需要用dp做。
(這個dp卡了我這個蒟蒻好長時間QAQ)
設dp[i][j]爲處理到第i個蓄水廠時覆蓋前j座城市所需要建造的最少的蓄水廠數,可知

dp[i][j]=min(dp[i-1][j],dp[i-1][Point[1][i].l-1]+1);

發現第一維可以省略掉,轉移方程爲

dp[j]=min(dp[j],dp[Point[1][i].l-1]+1);

代碼(o°ω°o)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

int N,M,cnt;
int h[510][510],dp[510];
int x[4]={0,1,0,-1},
    y[4]={1,0,-1,0};
struct maple{
    int l,r,used;
}Point[510][510];

void dfs(int X,int Y)
{
    Point[X][Y].used=1;
    if(X==N)  ++cnt,Point[X][Y]=(maple){Y,Y,1};
    for(int i=0;i<=3;++i)
    {
        int xx=X+x[i],yy=Y+y[i];
        if(xx>0&&xx<=N&&yy>0&&yy<=M&&h[xx][yy]<h[X][Y])
        {
            if(Point[xx][yy].used)
            {
                Point[X][Y].r=max(Point[X][Y].r,Point[xx][yy].r);
                if(Point[xx][yy].l&&Point[X][Y].l) Point[X][Y].l=min(Point[X][Y].l,Point[xx][yy].l);
                else if(!Point[X][Y].l) Point[X][Y].l=Point[xx][yy].l;
            } 
            else
            {
               dfs(xx,yy);
               Point[X][Y].r=max(Point[X][Y].r,Point[xx][yy].r);
               if(Point[X][Y].l&&Point[xx][yy].l) Point[X][Y].l=min(Point[X][Y].l,Point[xx][yy].l);
               else if(!Point[X][Y].l) Point[X][Y].l=Point[xx][yy].l;
            }
        }
    }
}
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)
       if(!Point[1][i].used)
          dfs(1,i);
    if(cnt!=M) 
    {
        printf("0\n%d",M-cnt);
        return 0;
    }
    memset(dp,63,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=M;++i)
       for(int j=Point[1][i].l;j<=Point[1][i].r;++j)
          dp[j]=min(dp[j],dp[Point[1][i].l-1]+1);
    printf("1\n%d",dp[M]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章