题目:Substring
题意:给你一个有向图, 一共有n个节点 , m条变, 一条路上的价值为这个路上出现过的某个字符最多出现次数, 现求这个最大价值, 如果价值可以无限大就输出-1。
题解:当这个有向图构成一个环的时候就会使得值无限大,所以先用拓扑排序判断一下有没有环,如果有环直接输出-1, 如果没有环就再使用树形dp并记忆化存数,来找到最大值。
代码:
1 #include<cstring> 2 #include<iostream> 3 using namespace std; 4 const int N = 300000+5; 5 string str; 6 int head[N], c[N], topo[N], dp[N][26]; 7 int cnt = 0, n, m, k, ans = 0; 8 struct Node 9 { 10 int nx; 11 int to; 12 }Edge[N]; 13 void add_edge(int u, int v) 14 { 15 Edge[cnt].to = v; 16 Edge[cnt].nx = head[u]; 17 head[u] = cnt++; 18 } 19 bool dfs(int u) 20 { 21 c[u] = -1; 22 for(int i = head[u]; ~i; i = Edge[i].nx) 23 { 24 int v = Edge[i].to; 25 if(c[v] < 0) return false; 26 else if(!c[v] && !dfs(v)) return false; 27 } 28 c[u] = 1; 29 topo[--k] = u; 30 return true; 31 } 32 bool topo_sort() 33 { 34 k = n; 35 memset(c, 0, sizeof(c)); 36 for(int i = 0; i < n; i++) 37 { 38 if(!c[i]) 39 if(!dfs(i)) return false; 40 } 41 return true; 42 } 43 void dfs_count(int u) 44 { 45 c[u] = 1; 46 for(int i = head[u]; ~i; i = Edge[i].nx) 47 { 48 int v = Edge[i].to; 49 if(!c[v]) dfs_count(v); 50 for(int i = 0; i < 26; i++) 51 { 52 if(dp[u][i] < dp[v][i]) 53 { 54 dp[u][i] = dp[v][i]; 55 int tmp = (str[u]-'a' == i)? dp[u][i]+1 : dp[u][i]; 56 if(tmp > ans) ans = tmp; 57 } 58 } 59 } 60 dp[u][str[u]-'a']++; 61 } 62 int main() 63 { 64 ios::sync_with_stdio(false); 65 cin.tie(0); 66 memset(head, -1, sizeof(head)); 67 cin >> n >> m; 68 cin >> str; 69 int u, v; 70 for(int i = 1; i <= m; i++) 71 { 72 cin >> u >> v; 73 add_edge(u-1, v-1); 74 } 75 if(!topo_sort()) 76 { 77 cout << -1 << endl; 78 return 0; 79 } 80 memset(c, 0, sizeof(c)); 81 for(int i = 0; i < n; i++) 82 { 83 if(!c[topo[i]]) 84 dfs_count(topo[i]); 85 } 86 cout << ans << endl; 87 }