题目链接:P1514 [NOIP2010 提高组] 引水入城 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题意:
路只能严格由高到低,问从第一行的任意点出发,是否能经过最后一行的所有点?如果不行,有几个点没法到达;如果可以,最少需要多少个点作为出发点。
思路:
假设可以完成,那么对于一个点出发到最后一行能到达的位置一定是一段连续的区间。
假设存在点1到达最后一行的点不是连续,那么中间的部分必然有其他的起点来连接,则连接的过程和点1到最后一行的路径必然有重叠的点,说明该重叠的点可以通往中间部分,说明假设有误。
对于最小的区间查找,首先要以左边为基点,找到一个区间能包含左边,同时靠右端最近,然后更新左端点为该区间的最右处+1;再遍历重复这个过程。
代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <iostream>
#include <algorithm>
#define ll long long
#define pi 3.1415926
using namespace std;
const int MAXN=1e6;
const int mod=6e5;
const int N=505;
int X1,Y1,X2,Y2;
struct node{
double x,y;
}s[N];
void test(int x){
cout<<x<<endl;
}
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int l[N][N],r[N][N];//代表该点最远能到达的左和右
int road[N][N];
int vis[N][N]={0};
int n,m;
void dfs(int x,int y){
vis[x][y]=1;
for(int i=0;i<4;i++){
int tx=x+dx[i];
int ty=y+dy[i];
//是否走过,走过不用再搜,但是需要更新区间
//如果不符合规范的点,也不必继承下面的更新
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&road[x][y]>road[tx][ty]){
if(vis[tx][ty]==0) dfs(tx,ty);
l[x][y]=min(l[x][y],l[tx][ty]);
r[x][y]=max(r[x][y],r[tx][ty]);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
memset(l,0x3f3f3f,sizeof(l));//因为查找左区间的时候是尽量小,初始化就是尽量大;右区间最小为0不用再操作了
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>road[i][j];
}
}
for(int i=1;i<=m;i++){
l[n][i]=r[n][i]=i;//初始化最后一行的每一个点能区间为自己本身
}
for(int i=1;i<=m;i++){
if(vis[1][i]!=1) dfs(1,i);
}
int count=0;
bool flag=false;
for(int i=1;i<=m;i++){
if(vis[n][i]==0){
flag=true;
count++;
}
}
int ans=0;
if(flag){
cout<<0<<endl<<count<<endl;
return 0;
}
else{
int left=1;
//test(left);
int right=r[1][1];
while(right!=m){
for(int i=1;i<=m;i++){
if(l[1][i]<=left){
right=max(right,r[1][i]);
}
}
left=right+1;
ans++;
}
}
cout<<1<<endl<<ans<<endl;
return 0;
}
文章讲述了NOIP2010提高组竞赛中的一道图论问题——引水入城。题目要求判断从第一行的任意一点出发能否到达最后一行的所有点,并求出最少需要多少个出发点。解题思路基于动态规划,通过DFS搜索确定每个点能到达的最远位置,并找到覆盖所有最后一行点的最小区间。最后给出了C++实现的代码示例。
517

被折叠的 条评论
为什么被折叠?



