洛谷P1514 引水入城
阿新 • • 發佈:2018-12-13
題目連結
解題思路:
綜合考察了搜尋和區間合併。
難點在於記錄最後一行區間的左右端點,還有從第一行開始搜時,注意優化一下,並不是第一行的每列作為起點開始搜,而是比左右端點都大的列開始搜,可以節省時間。
區間合併注意排序。
include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxv=233233233;
int map[510][510],vis[510][510];
int flag[510];
int g[][2]={-1,0,1,0,0,1,0,-1};//前進的四個方向
int n,m;
struct qujian{//區間
int l,r;
}c[510];
bool cmp(qujian A,qujian B){//區間合併,首先升序
if(A.l==B.l) return A.r<B.r;
return A.l<B.l;
}
void dfs(int x,int y,int index){//座標x,y,以及第一行開始搜尋的點index
if(x==n){
c[index].l=min(c[index].l,y);//區間標記
c[index].r=max(c[index] .r,y);
flag[y]=1;
}
for(int i=0;i<4;i++){
int nx=x+g[i][0];
int ny=y+g[i][1];
if(nx<1||nx>n||ny<1||ny>m) continue;
if(!vis[nx][ny]&&map[x][y]>map[nx][ny]){
vis[nx][ny]=1;
dfs(nx,ny,index);
}
}
}
//int test(){
// for(int i=1;i<=m;i++){
// if(!vis[n][i]) return 1;//未訪問完
// }
// return 0;
//}
int main(int argc, char** argv) {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&map[i][j]);
if(i==1) c[j].l=maxv;
}
}
for(int i=1;i<=m;i++){
if(map[1][i]>=map[1][i-1]&&map[1][i]>=map[1][i+1]){//優化1,從第一行選擇滿足條件的點開始往下搜
memset(vis,0,sizeof(vis));
dfs(1,i,i);
}
}
int cnt=0;
for(int j=1;j<=m;j++){
if(!flag[j]) cnt++;//如果flag[j]==0,說明最後一行第j列沒有被訪問到。
}
if(cnt==0){
sort(c+1,c+m+1,cmp);//升序
int len=m;
while(c[m].l==maxv) --m;//除去之前未訪問的值
// for(int i=1;i<=m;i++)
// printf("%d %d\n",c[i].l,c[i].r);
//排序之後區間合併
int i1=1,tr=1,ans=0;//區間左端點,右端點,累計的值ans
while(tr<=len){
int temp=0;
while(c[i1].l<=tr){
temp=max(temp,c[i1].r);
i1++;
}
tr=temp+1;
ans+=1;
}
printf("1\n%d\n",ans);
}
else{
printf("0\n%d\n",cnt);
}
return 0;
}