您的位置:首页 > 其它

CF 460 div2 D 题 Substring 【拓扑序 + dp】

2018-02-01 00:12 495 查看
传送门

// 给定一幅有向图, 每个点上有一个字母, 定义一条路径的长度为该路径上的点的字母出现次数最多的那个字母次数, 现在问你最长的路径长度是多少.

// 思路: 很明显的拓扑序, 有一个问题就是到了一个点后我们要求出到该点的所有路径中26个字母中出现的最大次数并保存下来, 也就是我们设dp[i][j] 代表到i这个点时j字母出现的次数最大是多少. 每次到一个点后就维护下这些信息. 每次推出来的点加上本身的, 最后扫一遍得出ans即可.

注意判环, 我们可以最后在扫一遍in, 如果还有in != 0 的 , 那么就一定有环了.

AC Code

const int maxn = 3e5+5;
int cas=1;
vector<int>g[maxn];
int dp[maxn][30];
int in[maxn], a[maxn];
void solve()
{
int n, m;
scanf("%d%d", &n, &m);
string s; cin >> s;
for (int i = 0 ; i < s.size() ; i ++) a[i+1] = s[i] - 'a' + 1;
for (int i = 1 ; i <= m ; i ++) {
int u, v;
scanf("%d%d",&u, &v);
g[u].pb(v);
in[v]++;
}
queue<int>q;
for (int i = 1 ; i <= n ; i ++) {
if (!in[i]) q.push(i);
}
while(!q.empty()) {
int u = q.front();
q.pop();
dp[u][a[u]]++;

for (auto to : g[u]) {
for (int i = 1 ; i <= 26 ; i ++) {
dp[to][i] = max(dp[to][i], dp[u][i]);
}
in[to]--;
if (!in[to]) q.push(to);
}
}
int ans = 0;
for (int i = 1 ; i <= n ; i ++) {
for (int j = 1 ; j <= 26 ; j ++) {
ans = max(ans, dp[i][j]);
}
}
for (int i = 1 ; i <= n ; i ++) {
if (in[i]) {
ans = -1;
break;
}
}
printf("%d\n", ans);
}


当然也可以用判有向图是否有环的板子(.jpg
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: