Codeforces 919D Substring (拓扑图DP)
手动博客搬家: 本文发表于20180716 10:53:12, 原地址https://blog.csdn.net/suncongbo/article/details/81061500
给定一个\(n\)个点\(m\)条边的有向图(不一定无环),每个点上有一个小写字母。要找一条路径,使得路径上出现次数最多的字母出现的次数最多。如果答案为无穷大输出-1.
题解:何时无穷大?有环的时候可以不停地走环,统计无限次答案,答案为无穷大。因此,对于-1的情况,只需要判一下环即可。
对于有限大的情况,令\(dp[i][c]\)表示以第\(i\)个节点结束的路径中含有\(c\)这个字母次数的最大值。则有\(dp[i][c]=\max_{j\in ind[i]}{dp[j][c]}+[a[i]==c]\), \(a[i]\)为第\(i\)个点的字母。
然后就可以得到答案了。时间复杂度\(O(mS)\), S为字符集大小26.
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 3e5;
const int S = 26;
struct Edge
{
int v,nxt; bool used;
} e[N+3];
int fe[N+2];
char s[N+2];
int a[N+2];
int dfn[N+2],low[N+2];
int sta[N+2];
bool ins[N+2],vis[N+2];
int dp[N+2][S+2];
int ind[N+2];
int que[N+2];
int n,m,tp,mx,head,tail,tot;
void addedge(int u,int v)
{
e[++m].v = v; e[m].nxt = fe[u]; fe[u] = m;
}
void Tarjan(int u)
{
dfn[u] = low[u] = ++tp; sta[tp] = u; ins[u] = true;
for(int i=fe[u]; i; i=e[i].nxt)
{
int v = e[i].v;
if(!dfn[v]) {Tarjan(v); low[u] = min(low[v],low[u]);}
else if(ins[v]) low[u] = min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
int tmp = 1;
while(sta[tp]!=u && tp>0)
{
int v = sta[tp];
ins[v] = false;
tp--; tmp++;
}
ins[u] = false; tp--;
if(tmp>mx) mx = tmp;
}
}
int main()
{
int m0; m = 0;
scanf("%d%d",&n,&m0);
scanf("%s",s+1); for(int i=1; i<=n; i++) a[i] = (int)s[i]-'a'+1;
for(int i=1; i<=m0; i++) {int x,y; scanf("%d%d",&x,&y); addedge(x,y); if(x==y) {printf("-1\n"); return 0;}}
for(int i=1; i<=n; i++) {if(!dfn[i]) Tarjan(i);}
if(mx>1) {printf("-1\n"); return 0;}
for(int i=1; i<=n; i++)
{
for(int j=fe[i]; j; j=e[j].nxt) ind[e[j].v]++;
}
tot = 0;
for(int i=1; i<=n; i++) dp[i][a[i]] = 1;
while(tot<n)
{
for(int j=1; j<=n; j++)
{
if(ind[j]==0 && vis[j]==false)
{
tail++;
que[head] = j; vis[j] = true; tot++;
while(head<=tail)
{
int c = que[head++];
for(int i=fe[c]; i; i=e[i].nxt)
{
if(e[i].used) continue;
e[i].used = true;
ind[e[i].v]--;
for(int k=1; k<=S; k++)
{
if(a[e[i].v]==k) dp[e[i].v][k] = max(dp[e[i].v][k],dp[c][k]+1);
else dp[e[i].v][k] = max(dp[e[i].v][k],dp[c][k]);
}
if(ind[e[i].v]==0 && vis[e[i].v]==false)
{
vis[e[i].v] = true; tot++;
que[++tail] = e[i].v;
}
}
}
}
}
}
int ans = 0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=S; j++) ans = max(ans,dp[i][j]);
}
printf("%d\n",ans);
return 0;
}
Codeforces 919D Substring (拓扑图DP)的更多相关文章
- Codeforces 919D - Substring
919D - Substring 思路: 拓扑排序判环+DAG上dp+记忆化搜索 状态:dp[i][j]表示以i为起点的路径中j的最大出现次数 初始状态:dp[i][j]=1(i have no so ...
- Codeforces 919D Substring (拓扑排序+树形dp)
题目:Substring 题意:给你一个有向图, 一共有n个节点 , m条变, 一条路上的价值为这个路上出现过的某个字符最多出现次数, 现求这个最大价值, 如果价值可以无限大就输出-1. 题解:当这个 ...
- Codeforces 919D Substring 【拓扑排序】+【DP】
<题目链接> 题目大意:有一个具有n个节点,m条边的有向图,每个点对应一个小写字母,现在给出每个顶点对应的字母以及有向边的连接情况,求经过的某一条路上相同字母出现的最多次数.如果次数无限大 ...
- CodeForces - 919D Substring (拓扑排序+dp)
题意:将一个字符串上的n个字符视作点,给出m条有向边,求图中路径上最长出现的相同字母数. 分析:首先如果这张图中有环,则可以取无限大的字符数,在求拓扑排序的同时可以确定是否存在环. 之后在拓扑排序的结 ...
- Codeforces 919D Substring ( 拓扑排序 && DAG上的DP )
题意 : 给出含有 N 个点 M 条边的图(可能不连通或者包含环),每个点都标有一个小写字母编号,然后问你有没有一条路径使得路径上重复字母个数最多的次数是多少次,例如图上有条路径的顶点标号顺序是 a ...
- 微软2016校园招聘在线笔试 B Professor Q's Software [ 拓扑图dp ]
传送门 题目2 : Professor Q's Software 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Professor Q develops a new s ...
- [Codeforces 1201D]Treasure Hunting(DP)
[Codeforces 1201D]Treasure Hunting(DP) 题面 有一个n*m的方格,方格上有k个宝藏,一个人从(1,1)出发,可以向左或者向右走,但不能向下走.给出q个列,在这些列 ...
- Codeforces 919D:Substring(拓扑排序+DP)
D. Substring time limit: per test3 seconds memory limit: per test256 megabytes inputstandard: input ...
- CodeForces 163A Substring and Subsequence dp
A. Substring and Subsequence 题目连接: http://codeforces.com/contest/163/problem/A Description One day P ...
随机推荐
- Linux系统编程——特殊进程之僵尸进程
僵尸进程(Zombie Process) 进程已执行结束,但进程的占用的资源未被回收.这种进程称为僵尸进程. 在每一个进程退出的时候,内核释放该进程全部的资源.包含打开的文件.占用的内存等. 可是仍然 ...
- 【Linux】Linux下配置apache
一.获取软件: http://httpd.apache.org/ httpd-2.4.10.tar.gz 二.安装步骤: 解压源文件: 1) tar zvxf httpd-2.4.10.tar. ...
- 剑指Offer——面试小提示(持续更新中)
(1)应聘者在电话面试的时候应尽可能用形象的语言把细节说清楚. (2)假设在英语面试时没有听清或没有听懂面试官的问题,应聘者要敢于说Pardon. (3)在共享桌面远程面试中.面试官最关心的是应聘者的 ...
- framebuffer的入门介绍-实现程序分析【转】
本文转载自:http://blog.csdn.net/liuzijiang1123/article/details/46972723 如想想对lcd屏进行操作(例如在lcd屏幕上画线,或者显示视频数据 ...
- 排序系列 之 归并排序算法 —— Java实现
基本思想: 归并排序法是分治法的典型实例,分为分割和归并两部分. 把一个数组分为大小相近的子数组(分割),分别把子数组排好序后,通过合成一个大的排好序的数组(归并). 实例: 先分割成每个子序列只有一 ...
- Check the difficulty of problems(概率+DP)
http://poj.org/problem?id=2151 看的题解..表示没看懂状态转移方程.. #include<stdio.h> #include<string.h> ...
- .Net Core 学习(二)上篇
用Visual Studio和ASP.NET Core MVC创建Web API 1.启动Visual Studio.从文件菜单,选择新建>项目.选择ASP.NET Core Web Appli ...
- PHP序列化 反序列化
序列化是将变量转换为可保存或传输的字符串的过程:反序列化就是在适当的时候把这个字符串再转化成原来的变量使用.这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性. 1. serialize和 ...
- buf.readInt8函数详解
offset {Number} 0 noAssert {Boolean} 默认:false 返回:{Number} 从该 Buffer 指定的 offset 位置开始读取一个有符号的8位整数值. 设置 ...
- 我和CSDN的那些事
作者:朱金灿 来源:http://blog.csdn.net/clever101 前些日子收到这样一个邀请: CSDN的工作人员还来电给我确认是否能参加.开始我有点犹豫,毕竟是在工作日的晚上,毕竟离我 ...