Loading

POJ-2375 Cow Ski Area

Cow Ski Area

把一个图变成一个强连通图

\(tarjan\)

考虑 \(tarjan\) 缩点之后形成若干个 \(DAG\) 图,接下来就是将这若干个 \(DAG\) 图连接起来

不难发现我们先让所有的图首尾相连(入度为 \(0\) 和 出度为 \(0\)),使得所有的 \(DAG\) 图可以互相到达(环)

接着如果一个图的开始结点或结束结点大于 \(2\) 的情况,就考虑将未匹配的首尾(不用管是哪个图的)互相连接

这样一想,答案就应该是所有图的开始点(入度为 \(0\) )数量之和和结束点(出度为 \(0\) )数量之和的最大值

如果只有一个强联通分量的时候,答案为 \(0\),记得特判

坑坑坑:

  1. 数组大小,考虑如果所有点数字相同,到底要开多少的边

  2. \(vector\),速速改成链式前向星

  3. 如果 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;
}
posted @ 2022-08-12 15:20  dgsvygd  阅读(17)  评论(0编辑  收藏  举报