手动博客搬家: 本文发表于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)的更多相关文章

  1. Codeforces 919D - Substring

    919D - Substring 思路: 拓扑排序判环+DAG上dp+记忆化搜索 状态:dp[i][j]表示以i为起点的路径中j的最大出现次数 初始状态:dp[i][j]=1(i have no so ...

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

    题目:Substring 题意:给你一个有向图, 一共有n个节点 , m条变, 一条路上的价值为这个路上出现过的某个字符最多出现次数, 现求这个最大价值, 如果价值可以无限大就输出-1. 题解:当这个 ...

  3. Codeforces 919D Substring 【拓扑排序】+【DP】

    <题目链接> 题目大意:有一个具有n个节点,m条边的有向图,每个点对应一个小写字母,现在给出每个顶点对应的字母以及有向边的连接情况,求经过的某一条路上相同字母出现的最多次数.如果次数无限大 ...

  4. CodeForces - 919D Substring (拓扑排序+dp)

    题意:将一个字符串上的n个字符视作点,给出m条有向边,求图中路径上最长出现的相同字母数. 分析:首先如果这张图中有环,则可以取无限大的字符数,在求拓扑排序的同时可以确定是否存在环. 之后在拓扑排序的结 ...

  5. Codeforces 919D Substring ( 拓扑排序 && DAG上的DP )

    题意 : 给出含有 N 个点 M 条边的图(可能不连通或者包含环),每个点都标有一个小写字母编号,然后问你有没有一条路径使得路径上重复字母个数最多的次数是多少次,例如图上有条路径的顶点标号顺序是  a ...

  6. 微软2016校园招聘在线笔试 B Professor Q's Software [ 拓扑图dp ]

    传送门 题目2 : Professor Q's Software 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Professor Q develops a new s ...

  7. [Codeforces 1201D]Treasure Hunting(DP)

    [Codeforces 1201D]Treasure Hunting(DP) 题面 有一个n*m的方格,方格上有k个宝藏,一个人从(1,1)出发,可以向左或者向右走,但不能向下走.给出q个列,在这些列 ...

  8. Codeforces 919D:Substring(拓扑排序+DP)

    D. Substring time limit: per test3 seconds memory limit: per test256 megabytes inputstandard: input ...

  9. CodeForces 163A Substring and Subsequence dp

    A. Substring and Subsequence 题目连接: http://codeforces.com/contest/163/problem/A Description One day P ...

随机推荐

  1. 我对ThreadLocal的理解

    声明:小弟菜狗一个.对ThreadLocal的描写叙述和理解难免有所偏差 近期由于须要深入的了解android的handler消息机制而去查看了Looper的源代码.众所周知在主线程中是不须要在程序猿 ...

  2. mysql-5.5 for linux源码安装

    mysql-5.5 for linux源码安装 1.使用Yum安装依赖软件包 # yum install -y gcc gcc-c++ gcc-g77 autoconf automake bison  ...

  3. bzoj5130: [Lydsy1712月赛]字符串的周期

    这道题很有意思啊. 字符串循环节用KMP(手推一下) 假如是26^12肯定很不滋磁 但是可以发现ABA和BCB和BAB这些都是等价的 那就把最小的拿出来搞再乘个排列数就好了 #include<c ...

  4. HDU 3887 Counting Offspring(DFS序+树状数组)

    Counting Offspring Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  5. 【POJ 3630】 Phone List

    [题目链接] http://poj.org/problem?id=3630 [算法] 字典树 [代码] #include <algorithm> #include <bitset&g ...

  6. 【转】iPhone获取状态栏和导航栏尺寸(宽度和高度)

    原文网址:http://blog.csdn.net/chadeltu/article/details/42708605 iPhone开发当中,有时需要获取状态栏和导航栏高度.宽度信息,方便布局其他控件 ...

  7. 关于form/input 的autocomplete="off"属性

    转自:http://blog.sina.com.cn/s/blog_b49f96a701019m0d.html 一. 有过表单设计经验的朋友肯定知道,当我们在浏览器中输入表单信息的时候,往往input ...

  8. DNS(域名系统)

    DNS(Domain Name System),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的Ip数串.通过主机名,最终得到该主机 ...

  9. POJ 1160 DP

    题目: poj 1160 题意: 给你n个村庄和它的坐标,现在要在其中一些村庄建m个邮局,想要村庄到最近的邮局距离之和最近. 分析: 这道题.很经典的dp dp[i][j]表示建第i个邮局,覆盖到第j ...

  10. 6.10---mybatis的实体---接口---接口映射---主配置文件