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

洛谷P1514 引水入城

題目連結
解題思路:

綜合考察了搜尋和區間合併。
難點在於記錄最後一行區間的左右端點,還有從第一行開始搜時,注意優化一下,並不是第一行的每列作為起點開始搜,而是比左右端點都大的列開始搜,可以節省時間。
區間合併注意排序。

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; }