题目传送门

这道题开始看好像并没有什么思路,和搜索好像也并没有什么关系。但是我们手玩下样例就会发现,思路其实就三句话:(写这道题的时候在代码里写的)

  • //我们想知道从第1行的每列往下到干旱区的范围

  • //要求这个直接bfs就行了

  • //然后就转换为了一个最小线段覆盖了

写了个bfs,在学长的blog那里看了看线段覆盖怎么搞,于是就交了,开始是30分,因为bfs的时候我只用了3个方向。开始以为它是不能向上建水站的,后来想想其实也可以,只要满足有公共边+高度有落差就行了...再交就90分了\(qwq\),T了一个点,开了氧气优化+快读,然后A了(???)

// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue> using namespace std; int n,m,ans,tot;
int la[600][600],tong[600],fla[600];
bool vis[600][600];
int dx[5]={0,0,1,0,-1};
int dy[5]={0,-1,0,1,0};
struct segment{
int l,r;
}p[600]; void re(int &x)
{
x=0;
char ch=getchar();
bool flag=false;
while(ch<'0'||ch>'9') flag|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x=flag ? -x : x;
} bool valid(int x,int y)
{
if(x>=1&&x<=n&&y>=1&&y<=m) return 1;
return 0;
} bool cmp(segment x,segment y)
{
return x.l<y.l;
} void bfs(int x,int y)
{
memset(vis,0,sizeof(vis));
queue<pair<int,int> >q;
q.push(make_pair(x,y));
vis[x][y]=1;
while(!q.empty())
{
int nx=q.front().first;
int ny=q.front().second;
q.pop();
for(int i=1;i<=4;i++)
{
int xx=nx+dx[i];
int yy=ny+dy[i];
if(valid(xx,yy)&&la[nx][ny]>la[xx][yy]&&!vis[xx][yy])
q.push(make_pair(xx,yy)),vis[xx][yy]=1;
}
}
int l=99999,r=0;
for(int j=1;j<=m;j++)
if(vis[n][j]) tong[y]++,fla[j]++,l=min(l,j),r=max(r,j);
if(!tong[y]) return ;
p[++tot].l=l,p[tot].r=r;
} int main()
{
//我们想知道从第1行的每列往下到干旱区的范围
//要求这个直接bfs就行了
//然后就转换为了一个最小线段覆盖了
re(n);re(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
re(la[i][j]);
for(int j=1;j<=m;j++)
bfs(1,j);
// for(int j=1;j<=m;j++) printf("%d %d\n",p[j].l,p[j].r);
for(int j=1;j<=m;j++)
if(!fla[j]) ans++;
if(ans) {printf("0\n%d",ans);return 0;}
sort(p+1,p+tot+1,cmp);
int s=1;
for (int i=1;i<=m;i++)
{
int r=0;
for (int j=1;j<=m;j++)
if (p[j].l<=s&&p[j].r>=s) r=max(r,p[j].r);
ans++;
s=r+1;
if (s>m) break;
}
printf("1\n%d",ans);
return 0;
}

为什么会T呢?刚才我们的算法复杂度其实严格是\(O(n^3+nlogn+n^2)\)的。开始不解为什么搜索会是\(O(n^3)\),想了想后发现这是网格图,遍历所有点一遍是\(O(n^2)\)的。而本题极限数据\(500\),可能会跑到一亿,超时。

刚才我们有最直观的想法:从第一行的每列出发向下搜索,但事实上我们可以不对所有第一行的位置进行向下搜索。只对那些满足\(h[1][i]>=h[1][i-1]\)而且\(h[1][i]>=h[1][i+1]\)的点进行搜索。因为当前点如果不满足这些条件,那么它形成的区间一定可以被其他区间覆盖,这个区间就没什么用了。

// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue> using namespace std; int n,m,ans,tot;
int la[600][600],tong[600],fla[600];
bool vis[600][600];
int dx[5]={0,0,1,0,-1};
int dy[5]={0,-1,0,1,0};
struct segment{
int l,r;
}p[600]; void re(int &x)
{
x=0;
char ch=getchar();
bool flag=false;
while(ch<'0'||ch>'9') flag|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x=flag ? -x : x;
} bool valid(int x,int y)
{
if(x>=1&&x<=n&&y>=1&&y<=m) return 1;
return 0;
} bool cmp(segment x,segment y)
{
return x.l<y.l;
} void bfs(int x,int y)
{
memset(vis,0,sizeof(vis));
queue<pair<int,int> >q;
q.push(make_pair(x,y));
vis[x][y]=1;
while(!q.empty())
{
int nx=q.front().first;
int ny=q.front().second;
q.pop();
for(int i=1;i<=4;i++)
{
int xx=nx+dx[i];
int yy=ny+dy[i];
if(valid(xx,yy)&&la[nx][ny]>la[xx][yy]&&!vis[xx][yy])
q.push(make_pair(xx,yy)),vis[xx][yy]=1;
}
}
int l=99999,r=0;
for(int j=1;j<=m;j++)
if(vis[n][j]) tong[y]++,fla[j]++,l=min(l,j),r=max(r,j);
if(!tong[y]) return ;
p[++tot].l=l,p[tot].r=r;
} int main()
{
//我们想知道从第1行的每列往下到干旱区的范围
//要求这个直接bfs就行了
//然后就转换为了一个最小线段覆盖了
re(n);re(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
re(la[i][j]);
for(int j=1;j<=m;j++)
if(la[1][j]>=la[1][j-1]&&la[1][j]>=la[1][j+1])
bfs(1,j);
// for(int j=1;j<=m;j++) printf("%d %d\n",p[j].l,p[j].r);
for(int j=1;j<=m;j++)
if(!fla[j]) ans++;
if(ans) {printf("0\n%d",ans);return 0;}
sort(p+1,p+tot+1,cmp);
int s=1;
for (int i=1;i<=m;i++)
{
int r=0;
for (int j=1;j<=m;j++)
if (p[j].l<=s&&p[j].r>=s) r=max(r,p[j].r);
ans++;
s=r+1;
if (s>m) break;
}
printf("1\n%d",ans);
return 0;
}

Luogu P1514引水入城【搜索】 By cellur925的更多相关文章

  1. [luogu]P1514 引水入城[搜索][记忆化][DP]

    [luogu]P1514 引水入城 引水入城 题目描述在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形 ,如下图所示,其中每个格 ...

  2. 洛谷P1514 引水入城 [搜索,区间DP]

    题目传送门 引水入城 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个 N 行×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每 ...

  3. 【luogu P1514 引水入城】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1514 // luogu-judger-enable-o2 #include <iostream> ...

  4. Luogu P1514 引水入城

    我承认我有点懒(洛谷已经发过题解了,但我发誓要坚持写博客) 这道题坑了我3天…… 首先一看就与染色问题类似,果断BFS(写DFS炸了) 先将最上面(靠近水)的一行全部扔进队列里,做一遍BFS 再对最下 ...

  5. [NOIp2010] luogu P1514 引水入城

    跟 zzy, hwx 等人纠结是否回去上蛋疼的董老板的课. 题目描述 如图所示.你有一个 N×MN\times MN×M 的矩阵,水可以从一格流到与它相邻的格子,需要满足起点的海拔严格高于终点海拔.定 ...

  6. LUOGU P1514 引水入城 (bfs)

    传送门 解题思路 拉了很长的战线,换了好几种写法终于过了..首先每个蓄水场一定是对沙漠造成连续一段的贡献,所以可以$bfs$出每种状态,然后做一次最小区间覆盖,但这样的复杂度有点高.就每次只搜那些比左 ...

  7. Luogu 1514 引水入城 (搜索,动态规划)

    Luogu 1514 引水入城 (搜索,动态规划) Description 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N行M列的矩形,如上图 ...

  8. 洛谷 P1514 引水入城 解题报告

    P1514 引水入城 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个 NN 行 \times M×M 列的矩形,如上图所示,其中每个格 ...

  9. 洛谷P1514 引水入城

    洛谷P1514 引水入城 原题链接 一道好题...细节真多 第一次提交90分,然后就GG了,不知从何改起 其实比较简单吧... 首先,一个点的水流向最后一排,一定可以形成一个区间. 不行的话肯定GG ...

随机推荐

  1. UITextInputMode类的使用

    转载请注明:http://blog.sina.com.cn/s/blog_69081e060100v7ad.html   UITextInputMode大家看了是不是有些陌生呢?这个类是在4.2之后才 ...

  2. 理解vue ssr原理,自己搭建简单的ssr框架

    前言 大多数Vue项目要支持SSR应该是为了SEO考虑,毕竟对于WEB应用来说,搜索引擎是一个很大的流量入口.Vue SSR现在已经比较成熟了,但是如果是把一个SPA应用改造成SSR应用,成本还是有些 ...

  3. CyclicBarrier及CountDownLatch的使用

    CountDownLatch位于java.util.concurrent包下,是JDK1.5的并发包下的新特性. 首先根据Oracle的官方文档看看CountDownLatch的定义: A synch ...

  4. ZOJ3496 Assignment

    传送门 这题也是真恶心-- 题目大意是俩公司要运货,每条路有容量上限.然后B公司手里有p个--(技能点?)如果在一条路上放了x个技能点,这条路经过了y个货物,那么B公司就会收x*y的钱.现在要求的是, ...

  5. R文件报错

    res中drawable中的资源文件进行命名时只能用0-9或者a-z或者-,其他的东西不能使用,也禁止在重命名时开头使用大写字母

  6. bzoj4259

    fft 搞一个生成函数 对于每位A(j)=Σi=1->m (a[i]-b[i+j])^2*a[i]*b[i+j] 如果A(j)=0说明这位匹配 如果这位是*那么a[i]=0否则等于字母-'a'+ ...

  7. Python interview_python

    https://github.com/taizilongxu/interview_python 1 Python的函数参数传递 strings, tuples, 和numbers是不可更改的对象,而l ...

  8. project工期出现小数问题

    进入“选项”,点击“日程”,将默认“开始”.“结束”时间调整为“9点~18点.原为PREJECT 日历 (注意是日历~!!)默认的“8点~17点”,与preject系统默认时间“9点~18点”有差别~ ...

  9. Appleman and a Sheet of Paper

    题意: 给一纸条,两种操作: 1.将左侧长度为$x$的纸条向右翻折. 2.询问位于$[l,r]$的纸条总长度. 解法: 考虑启发式,每一次一个小纸条折叠我们可以看做是一次合并,如果我们每一次将较小的纸 ...

  10. Google浏览器如何加载本地文件

    Chrome浏览器加载本地文件 一般来说,为了安全起见,浏览器是不能通过load方法来加载本地文件的,load方法只能加载远程服务器上的文件. 在浏览器默认的情况下,试图加载一个本地文件,会出现交叉域 ...