1 条题解

  • 0
    @ 2025-8-24 21:27:35

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar One_JuRuo
    没实力的只会切水题的超级大蒟蒻

    搬运于2025-08-24 21:27:34,当前版本为作者最后更新于2023-09-11 15:30:29,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    如果把每个方格看作一个点,就是这道题的子任务 B 了。

    思路

    首先看到目标是保证任意方格可以互通,就可以想到应该是一道强连通分量的题,只要按照题目的要求建图,就可以得到一个有向图,那么用 tarjan 缩点后,就可以得到一个无环的有向图。

    这样一个无向图,对于每个有入度有出度的点,肯定都是按照顺序走,最后是无出度的点停下,所以我们肯定需要连一些从无出度的点出发的边。

    那么,对于无入度的点,如果起点不是这个点,就无法到达这个点,所以肯定也需要连一些到达这些点的边。

    无出度和无入度可以连在一起,令无出度的点有 xx 个,无入度的点有 yy 个,那么答案至少都是 min(x,y)\min(x,y)

    不过需要注意的是,不是无出度和无入度的点简单两两匹配就好,实际情况需要交叉连边,因为无出度和无入度的点一定有对应关系,那么连边时应该避免连成若干个环。但是这道题只需要得出连边数量,不需要得出如何连边,所以可以不用考虑。

    还有需要注意的是,如果缩完点,只剩下一个点,那么就不需要连边。

    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
    上传者