1.二维转成一维,变成点图
2.tarjan缩点,变成简单DAG,然后就像“校园网校园网--tarjan求缩点的两个经典问题-CSDN博客
变成SCC,即强连通图
3.就像上面说的,特判环,正常情况输出max{in为0的点,ou为0的点}
P1653 [USACO04DEC] Cow Ski Area G - 洛谷
#include<bits/stdc++.h>
using namespace std;
#define N 100011
typedef long long ll;
int n,m;
int a[505][505];
vector<int> mp[250004];
int low[250004],dfn[250004],sd[250004],cnt,c;
stack<int> st;
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int ou[250004],in[250004];
void tarjan(int u)
{
low[u]=dfn[u]=++cnt;
st.push(u);
for(int v:mp[u])
{
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}else
if(!sd[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
sd[u]=++c;
while(st.top()!=u)
{
sd[st.top()]=c;
st.pop();
}
st.pop();
}
}
void dfs(int x,int y)
{
int p1=(x-1)*m+y;
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)
{
if(a[x][y]>=a[tx][ty])
{
int p2=(tx-1)*m+ty;
mp[p1].push_back(p2);
}
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>m>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++)///二维转一维
{
for(int j=1;j<=m;j++)
{
dfs(i,j);
}
}
for(int i=1;i<=n*m;i++)///tarjan缩点
{
if(!dfn[i])
{
tarjan(i);
}
}
if(c==1) cout<<0;///是个环
else
{
for(int i=1;i<=n*m;i++)
{
for(int v:mp[i])
{
if(sd[i]!=sd[v])
{
ou[sd[i]]++;
in[sd[v]]++;
}
}
}
int s1=0,s2=0;
for(int i=1;i<=c;i++)
{
if(!ou[i]) s1++;
if(!in[i]) s2++;
}
cout<<max(s1,s2); ///DAG变SCC的经典问题
}
return 0;
}