P1653
题目传送门
看懂题目后,就会发现这就是一道 Tarjan 的模板题。
首先是连边,当一个点(记为
然后跑一遍 Tarjan。再遍历每一个强连通分量,如果他的出度为
最后,输出
因为一个强连通分量里面的任意两个点都是可以互相滑到的,如果一个强连通分量入度为
Code:
#include<bits/stdc++.h>
#define N 250005
using namespace std;
int n, m, h[505][505]={0};
vector<int> v[N];
int dfn[N], low[N], dfncnt=0;
int scc[N], sc=0, st[N], top=0;
int in[N]={0}, out[N]={0};
bool is_st[N];
int ans1=0, ans2=0;
void add(int x, int y){
if(x>1 && h[x][y]>=h[x-1][y]) v[(x-1)*m+y].push_back((x-2)*m+y);
if(x<n && h[x][y]>=h[x+1][y]) v[(x-1)*m+y].push_back(x*m+y);
if(y>1 && h[x][y]>=h[x][y-1]) v[(x-1)*m+y].push_back((x-1)*m+y-1);
if(y<m && h[x][y]>=h[x][y+1]) v[(x-1)*m+y].push_back((x-1)*m+y+1);
}
void Tarjan(int x){
dfn[x]=low[x]=++dfncnt;
st[++top]=x, is_st[x]=1;
for(int i=0;i<(int)v[x].size();i++){
int tmp=v[x][i];
if(!dfn[tmp]) Tarjan(tmp), low[x]=min(low[x], low[tmp]);
else if(is_st[tmp]) low[x]=min(low[x], dfn[tmp]);
}
if(dfn[x]==low[x]){
sc++;
while(st[top]!=x){
scc[st[top]]=sc;
is_st[st[top]]=0;
top--;
}
scc[st[top]]=sc;
is_st[st[top]]=0;
top--;
}
}
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>h[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
add(i, j);
}
}
for(int i=1;i<=n*m;i++){
if(!dfn[i]){
Tarjan(i);
}
}
for(int i=1;i<=n*m;i++){
for(int j=0;j<(int)v[i].size();j++){
int tmp=v[i][j];
if(scc[i]!=scc[tmp]){
in[scc[tmp]]++, out[scc[i]]++;
}
}
}
for(int i=1;i<=sc;i++){
if(!in[i]) ans1++;
if(!out[i]) ans2++;
}
if(sc==1) cout<<0;
else cout<<max(ans1, ans2);
return 0;
}