1 条题解
-
0
自动搬运
来自洛谷,原作者为

One_JuRuo
没实力的只会切水题的超级大蒟蒻搬运于
2025-08-24 21:27:34,当前版本为作者最后更新于2023-09-11 15:30:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
如果把每个方格看作一个点,就是这道题的子任务 B 了。
思路
首先看到目标是保证任意方格可以互通,就可以想到应该是一道强连通分量的题,只要按照题目的要求建图,就可以得到一个有向图,那么用 tarjan 缩点后,就可以得到一个无环的有向图。
这样一个无向图,对于每个有入度有出度的点,肯定都是按照顺序走,最后是无出度的点停下,所以我们肯定需要连一些从无出度的点出发的边。
那么,对于无入度的点,如果起点不是这个点,就无法到达这个点,所以肯定也需要连一些到达这些点的边。
无出度和无入度可以连在一起,令无出度的点有 个,无入度的点有 个,那么答案至少都是 。
不过需要注意的是,不是无出度和无入度的点简单两两匹配就好,实际情况需要交叉连边,因为无出度和无入度的点一定有对应关系,那么连边时应该避免连成若干个环。但是这道题只需要得出连边数量,不需要得出如何连边,所以可以不用考虑。
还有需要注意的是,如果缩完点,只剩下一个点,那么就不需要连边。
AC code
#include<bits/stdc++.h> using namespace std; int n,m,a[505][505],dfn[250005],low[250005],dcnt,num,id[250005],z[250005],top,in_z[250005],e[1000005],ne[1000005],h[250005],idx=1,in[250005],out[250005],ans1,ans2; inline void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;} inline int get(int i,int j){return (i-1)*m+j;} inline void ade(int i,int j) { if(i>1) { if(a[i][j]>=a[i-1][j]) add(get(i,j),get(i-1,j)); if(a[i][j]<=a[i-1][j]) add(get(i-1,j),get(i,j)); } if(j>1) { if(a[i][j]>=a[i][j-1]) add(get(i,j),get(i,j-1)); if(a[i][j]<=a[i][j-1]) add(get(i,j-1),get(i,j)); } } void dfs(int u) { dfn[u]=low[u]=++dcnt,z[++top]=u,in_z[u]=1; for(int i=h[u];i;i=ne[i]) if(!dfn[e[i]]) dfs(e[i]),low[u]=min(low[u],low[e[i]]); else if(in_z[e[i]]) low[u]=min(low[u],dfn[e[i]]); if(dfn[u]==low[u]) { ++num; while(z[top+1]!=u) id[z[top]]=num,in_z[z[top--]]=0; } } int main() { scanf("%d%d",&m,&n); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",&a[i][j]),ade(i,j); for(int i=1;i<=n*m;++i) if(!dfn[i]) dfs(i); for(int i=1;i<=n*m;++i) for(int j=h[i];j;j=ne[j]) if(id[i]!=id[e[j]]) ++in[id[e[j]]],++out[id[i]]; for(int i=1;i<=num;++i){if(!in[i]) ++ans1;if(!out[i]) ++ans2;} printf("%d",(num==1)?0:max(ans1,ans2)); return 0; }
- 1
信息
- ID
- 645
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者