洛谷 P1514 引水入城
阿新 • • 發佈:2018-04-20
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 引水入城