zoukankan      html  css  js  c++  java
  • 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_{jin 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
    "); return 0;}}
    	for(int i=1; i<=n; i++) {if(!dfn[i]) Tarjan(i);}
    	if(mx>1) {printf("-1
    "); 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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Coursera-Getting and Cleaning Data-week4-R语言中的正则表达式以及文本处理
    Coursera-Getting and Cleaning Data-Week3-dplyr+tidyr+lubridate的组合拳
    Coursera-Getting and Cleaning Data-Week2-课程笔记
    Coursera-Getting and Cleaning Data-week1-课程笔记
    Coursera系列-R Programming-Final Week-Assignment3 & 总结
    Coursera系列-R Programming第三周-词法作用域
    Coursera系列-R Programming第二周
    ACCESS应用笔记<五>——慢慢要学会做项目管理·
    使用ubuntu过程中遇到的问题汇总
    圆方树学习笔记
  • 原文地址:https://www.cnblogs.com/suncongbo/p/10305692.html
Copyright © 2011-2022 走看看