洛谷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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值