POJ-2375 Cow Ski Area
Cow Ski Area
把一个图变成一个强连通图
\(tarjan\)
考虑 \(tarjan\) 缩点之后形成若干个 \(DAG\) 图,接下来就是将这若干个 \(DAG\) 图连接起来
不难发现我们先让所有的图首尾相连(入度为 \(0\) 和 出度为 \(0\)),使得所有的 \(DAG\) 图可以互相到达(环)
接着如果一个图的开始结点或结束结点大于 \(2\) 的情况,就考虑将未匹配的首尾(不用管是哪个图的)互相连接
这样一想,答案就应该是所有图的开始点(入度为 \(0\) )数量之和和结束点(出度为 \(0\) )数量之和的最大值
如果只有一个强联通分量的时候,答案为 \(0\),记得特判
坑坑坑:
-
数组大小,考虑如果所有点数字相同,到底要开多少的边
-
卡 \(vector\),速速改成链式前向星
-
如果 G++ RE,C++ TLE,速速手写栈 or 快读
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
const int maxn = 510;
const int maxm = 510 * 510 * 4;
int xi[4] = {1, -1, 0, 0};
int yi[4] = {0, 0, 1, -1};
int h[maxn][maxn], vis[maxn * maxn];
int st[maxn * maxn], stt = 0;
int low[maxn * maxn], dfn[maxn * maxn], tp = 0;
int scc[maxn * maxn], cnt_scc = 0;
int in[maxn * maxn], out[maxn * maxn];
int n, m;
int head[maxn * maxn], nexx[maxm], to[maxm];
int stp = 0;
inline void add(int u, int v)
{
stp++;
nexx[stp] = head[u];
head[u] = stp;
to[stp] = v;
}
inline bool check(int x, int y)
{
return x >= 0 && x < m && y >= 0 && y < n;
}
void tarjan(int now)
{
vis[now] = 1;
st[++stt] = now;
dfn[now] = low[now] = ++tp;
for(int i=head[now]; i; i=nexx[i])
{
int nex = to[i];
if(dfn[nex] == 0)
{
tarjan(nex);
low[now] = min(low[nex], low[now]);
}
else if(vis[nex])
low[now] = min(low[nex], low[now]);
}
if(low[now] == dfn[now])
{
cnt_scc++;
while(st[stt] != now)
{
int x = st[stt--];
vis[x] = 0;
scc[x] = cnt_scc;
}
st[stt--] = 0;
vis[now] = 0;
scc[now] = cnt_scc;
}
}
int solve(int n)
{
for(int i=1; i<=n; i++)
{
for(int j=head[i]; j; j=nexx[j])
{
int nex = to[j];
if(scc[i] != scc[nex])
{
in[scc[nex]]++;
out[scc[i]]++;
}
}
}
int a = 0, b = 0;
for(int i=1; i<=cnt_scc; i++)
{
if(in[i] == 0) a++;
if(out[i] == 0) b++;
}
return max(a, b);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int cnt = 0;
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
cin >> h[i][j];
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
for(int k=0; k<4; k++)
{
int ii = i + xi[k];
int jj = j + yi[k];
if(check(ii, jj) && h[i][j] >= h[ii][jj])
{
add(i * n + j + 1, ii * n + jj + 1);
}
}
}
}
for(int i=1; i<=n*m; i++)
if(dfn[i] == 0) tarjan(i);
if(cnt_scc == 1) {cout << 0 << endl; return 0;}
cout << solve(n * m) << endl;
return 0;
}