티스토리 뷰

[Codeforces 919D]Substring - 1700


문제 설명 : 

directed edge로 구성된 그래프가 있다. 그래프의 각 노드에는 알파벳이 배정되어있다. 그래프의 경로를 지나면서 거쳐가는 노드들의 알파벳중에서 최대 빈도수를 구하는 문제이다.  무수히 많은 빈도수가 나올 때는 -1을 출력한다.


풀이 : 

일단 그래프에서 사이클이 존재하는 경우 사이클 내에 있는 알파벳은 무수히 많이 등장할 수 있으므로 -1을 출력하면 된다. 만약 사이클이 없는게 확인된 그래프라면 위상정렬 알고리즘을 사용한다. 각 노드는 각 알파벳이 최대 몇 번 등장할 수 있는지 저장할 수 있는 freq[][]배열을 만든다. 그래서 다음 노드(next)에서 freq배열은 현재 노드의 freq배열과 같은 값을 가지면서, 다음 노드에 배정된 알파벳의 인덱스는 1 증가시켜주면 된다. 만약 next노드에 연결된 다른 노드들이 여러개라면 freq 배열의 값 중에서 가장 큰 값만 취하면 된다.

그래프에서 사이클을 판별하는 별도의 알고리즘이 있기는 하나, 나는 그냥 scc로 판별하기로 했다. 그 알고리즘은 레퍼런스로 따로 남기겠다.  실제로는 scc로 사이클을 판별할 필요도 없이 위상정렬 안의 while()문 안에서 pop()이 일어나는 횟수가 전체 노드 수(V)와 같은지 확인해주어도 사이클을 가지는지 판별해 줄 수 있다.


주의할 점 : 

-


배운 점 : 

사이클을 체크하고, 위상정렬까지 이용해야한다는 생각까지는 근접했는데 아깝게 풀지 못한 문제였다. 사이클을 체크하는데 scc보다는 간단한 알고리즘이 존재한다는 점, 그리고 그래프에서 시작점부터 끝점까지 봐야하는 경우(이 문제의 경우 최대한 긴 경로들의 집합을 만들어야 함) 위상정렬 알고리즘을 이용해야 한다.


코드 : 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<functional>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<assert.h>
#include<stdlib.h>
#include<stack>
using namespace std;
/*********************Contest Template***********************/
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<long long,long long> pll;
typedef pair<int,int> Cord;
#define FASTIO ios_base::sync_with_stdio(false);cin.tie(0);
struct S{
    int a,b; S(){}S(int _a,int _b){
        a=_a;
        b=_b;
    }
    const bool operator<(const S &o) const{
        return a<o.a;
    }
};
priority_queue<int,vector<int>,greater<int>> mpq;
#define SPACE 0
#define NL 1
inline void showAll(vector<int> &v,int NL_or_space){ 
    //0 is space, 1 is NL
    for(int &here:v){
        printf("%d",here);
        printf("%c",(NL_or_space)?'\n':' ');
    }
}
/*********************Contest Template***********************/
const int SIZE= 300009;
 
vector<int> graph[SIZE];
char str[SIZE];
int inD[SIZE],idx[SIZE],finished[SIZE];
int ans=1,cnt=1;
int freq[SIZE][33]={0};
vector<int> st;
 
int scc_dfs(int node){
    idx[node]=cnt++;
    int ret=idx[node];
    st.push_back(node);
 
    for(int next:graph[node]){
        if(idx[next]==0){
            ret=min(ret,scc_dfs(next));
        }
        else if(!finished[next]){
            ret=min(ret,idx[next]);
        }
    }
 
    if(ret==idx[node]){
        vector<int>tmp;
        while(1){
            int top=st.back();  st.pop_back();
            tmp.push_back(top);
            finished[top]=1;
            if(top==node) break;
        }
        if(tmp.size()>1) ans=-1;
    }
    return ret;
}
 
int main(){
    int V,E;    scanf("%d %d",&V,&E);
    scanf("%s",str+1);
 
    for(int i=0 ; i<E ; i++){
        int u,v;    scanf("%d %d",&u,&v);
        if(u==v){printf("-1\n"); return 0;}
        graph[u].push_back(v);
        inD[v]++;
    }
 
    for(int i=1 ; i<=V ; i++)
        if(idx[i]==0) scc_dfs(i);
 
    if(ans==-1){printf("-1\n"); return 0;}
 
    queue<int> q;
    for(int i=1 ; i<=V ; i++)
        if(inD[i]==0) q.push(i);
 
    int ans=0;
    while(!q.empty()){
        int cur=q.front();  q.pop();
        int &ret=freq[cur][str[cur]-'a'];
        ret++;
        ans=max(ans,ret);
 
        for(int next:graph[cur]){
            for(int i=0 ; i<26 ; i++){
                freq[next][i]=max(freq[next][i],freq[cur][i]);
            }
 
            if(--inD[next]==0){
                q.push(next);
            }
        }
    }
 
    printf("%d\n",ans);
    return 0;
}
 
 
cs


댓글