Codeforces 919D Substring (拓扑排序+树形dp)

题目: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 }

转载于:https://www.cnblogs.com/MingSD/p/8400745.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值