AcWing 1175. 최대 반연통 서브맵

24374 단어 tarjan

사고의 방향

  • 1.먼저 tarjan을 이용하여 모든 강연통 분량을 계산하여 그림을 유방향 무환도
  • 로 변경한다
  • 2.이 유방향 무환도에 대한 도면을 작성하고 중변
  • 을 제거한다.
  • 3.유방향 무환도에 대해 dp의 방식으로 f[i]는 i점을 종점으로 하는 가장 큰 연통자도 점의 개수를 나타낼 수 있다. g[i]는 이런 상황을 나타내는 방안수
  • 를 나타낸다.
  • 4.다음은 모든 방향이 있는 무환도의 점을 매거하고 각 점에 대해 매거변을 매거하여 dp를 하고 마지막으로 f 최대치를 구하면 된다
  • 코드

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    typedef long long LL;
    
    const int N = 100010, M = 2000010;
    
    int n, m, mod;
    int h[N], hs[N], e[M], ne[M], idx;
    int dfn[N], low[N], timestamp;
    stack<int> stk;
    bool in_stk[N];
    int id[N], scc_cnt, scc_size[N];
    int f[N], g[N];
    
    void add(int h[], int a, int b)
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    void tarjan(int u){
        dfn[u]=low[u]=++timestamp;
        stk.push(u);
        in_stk[u]=true;
        for(int i=h[u];~i;i=ne[i]){
            int j=e[i];
            if(!dfn[j]){
                tarjan(j);
                low[u]=min(low[u],low[j]);
            }
            else{
                if(in_stk[j]){
                    low[u]=min(low[u],low[j]);
                }
            }
        }
        if(dfn[u]==low[u]){
            ++ scc_cnt;
            int y;
            do{
                y=stk.top();
                stk.pop();
                in_stk[y] = false;
                id[y] = scc_cnt;
                scc_size[scc_cnt] ++ ;
            }while(y!=u);
        }
        
    }
    int main()
    {
        memset(h, -1, sizeof h);
        memset(hs, -1, sizeof hs);
    
        scanf("%d%d%d", &n, &m, &mod);
        while (m -- )
        {
            int a, b;
            scanf("%d%d", &a, &b);
            add(h, a, b);
        }
    
        for (int i = 1; i <= n; i ++ )
            if (!dfn[i])
                tarjan(i);
    
        unordered_set<LL> S;    // (u, v) -> u * 1000000 + v
        for (int i = 1; i <= n; i ++ )
            for (int j = h[i]; ~j; j = ne[j])
            {
                int k = e[j];
                int a = id[i], b = id[k];
                LL hash = a * 1000000ll + b;//   hash       
                if (a != b && !S.count(hash))//  
                {
                    add(hs, a, b);
                    S.insert(hash);
                }
            }
    
        for (int i = scc_cnt; i; i -- )
        {
            if (!f[i])//   
            {
                f[i] = scc_size[i];
                g[i] = 1;
            }
            for (int j = hs[i]; ~j; j = ne[j])
            {
                int k = e[j];
                if (f[k] < f[i] + scc_size[k])
                {
                    f[k] = f[i] + scc_size[k];
                    g[k] = g[i];
                }
                else if (f[k] == f[i] + scc_size[k])
                    g[k] = (g[k] + g[i]) % mod;
            }
        }
    
        int maxf = 0, sum = 0;
        for (int i = 1; i <= scc_cnt; i ++ )
            if (f[i] > maxf)
            {
                maxf = f[i];
                sum = g[i];
            }
            else if (f[i] == maxf) sum = (sum + g[i]) % mod;
    
        printf("%d
    "
    , maxf); printf("%d
    "
    , sum); return 0; }

    좋은 웹페이지 즐겨찾기