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

洛谷 P1514 引水入城

pan getc dig AS amp n) short sin 方向

這次不說閑話了,直接懟題


這道題用bfs其實並不難想,但比較困難的是怎麽解決滿足要求時輸出蓄水廠的數量。其實就像其他題解說的那樣,我們可以用bfs將它轉化成一個區間覆蓋問題,然後再進行貪心。

首先枚舉每個靠近湖泊的城市,假設它建有蓄水站,然後從它開始廣搜,搜到最後一行,也就靠近沙漠的城市後,記錄能建輸水站的一個區間。可能有人會問:如果一個蓄水站搜到的最後一行的區間不止一截,可能有多截怎麽辦呢? 我們可以這麽思考:如果它有多截,那麽每截中間肯定夾著一個(或一片)海拔比較高的城市,而且這個(片)城市的四面八方的海拔都比它小,那麽這就是無解的,那一個(片)城市是無法建造輸水站的。

我們在搜到最後一行時,記錄下能被搜到的城市,在全部搜完後,我們再掃一遍記錄的數組,如果都能被搜到,我們就用貪心去找最少的蓄水站,如果有城市是幹旱區,那就很好處理了,輸出無解+沒被掃到的城市數量

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()  //快讀
{
    short int k=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
      if(c=='-')  f=-1;
    for(;isdigit(c);c=getchar())
      k=k*10
+c-48; return k*f; } int vis[501][501]; int mapp[501][501]; //記錄地圖+尋找區間 struct zzz{ int x, y; }q[500*500+10]; int h=1,t; //搜索隊列 struct hhh{ int f, t; }xd[1001]; int tot; //記錄區間 bool cmp(hhh x,hhh y) //sort自定義比較函數 { if(x.f!=y.f) return x.f<y.f; else return x.t>y.t; } // 存四個方向
int fx[5]={0,1,0,-1,0}; int fy[5]={0,0,1,0,-1}; bool rqy[1001]; //存最後一行的城市是否被搜到過(聽說用神犇的名字做變量會RP++) int n,m; int main() { //======輸入 cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>mapp[i][j]; //======搜索 for(int i=1;i<=m;i++) { if(vis[1][i]) //這裏用了一個剪枝:如果靠近湖泊的城市海拔較高,那麽從這建一個蓄水站,旁邊靠近湖泊的城市就不用再建蓄水站了,直接建輸水站就行了,也就是說只要搜那海拔高的一個,就相當於把他周圍的海拔低的能建蓄水站的城市全搜過了 continue; memset(vis,0,sizeof(vis)); h=1; t=0; q[++t].x=1, q[t].y=i; vis[1][i]=i; if(n==1) //特別處理一下n=1時的測試點 rqy[i]=1; while(h<=t) //搜索主體 { for(int j=1;j<=4;j++) { int xx=q[h].x+fx[j],yy=q[h].y+fy[j]; if(xx<=0||yy<=0||xx>n||yy>m) continue; if(!vis[xx][yy]&&mapp[q[h].x][q[h].y]>mapp[xx][yy]) { q[++t].x=xx; q[t].y=yy; vis[xx][yy]=i; if(xx==n) rqy[yy]=1; } } h++; } //===記錄區間 bool www=0; for(int j=1;j<=m+1;j++) { if(vis[n][j]&&!www) { xd[++tot].f=j; www=1; } if(www&&!vis[n][j]) { xd[tot].t=j; break; } } } //======看每個城市能否被搜到 int jjj=0; for(int i=1;i<=m;i++) if(rqy[i]) jjj++; //如果不能全搜到 if(jjj!=m) { cout<<0<<endl<<m-jjj; return 0; } //可以全搜到,貪心線段覆蓋 sort(xd+1,xd+tot+1,cmp); int now=0,to=0,ans=0; for(int i=1;i<=tot-1;i++) { if(now>=xd[i].f) to=max(xd[i].t,to); else { ans++; now=to; to=max(to,xd[i].t); } } cout<<1<<endl<<ans; return 0; }

洛谷 P1514 引水入城