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

<题目链接>

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

解题分析:

因为是有向图并且是对完整路径进行操作,所以我们能够想到拓扑排序,同时拓扑排序也能够比较方便地判环。现在就是考虑如何得到路径中出现次数最多的字母个数,我们对每个节点,维护一个dp[u][j],表示u节点在所有通过u的道路中,截止到u节点,j 字母所出现的最大个数(其实就是最基础的DP思想)。

 #include <bits/stdc++.h>
 using namespace std;

 #define N int(3e5+7)
 #define rep(i,s,t) for(int i=s;i<=t;i++)
 char str[N];
 int n,m,cnt;
 struct Edge{
     int to,nxt;
 }edge[N];
 int head[N],deg[N];
 queue<int>que;
 ];       //dp[i][j]表示在所有经过i点的道路中,截止到i点,路径中第j种字母最大的数量

 template<typename T>
 inline T read(T&x){
     x=;;char ch=getchar();
     ')f|=(ch=='-'),ch=getchar();
     +ch-',ch=getchar();
     return x=f?-x:x;
 }
 void init(){
     cnt=;
     memset(head,-,sizeof(head));
 }
 void addedge(int u,int v){
     edge[cnt].to=v,edge[cnt].nxt=head[u];
     head[u]=cnt++;
 }
 bool topo() {
     ;
     while(!que.empty()){
         num++;
         int u=que.front();que.pop();
         for(int i=head[u];~i;i=edge[i].nxt){
             int v=edge[i].to;
             deg[v]--;
             if(!deg[v])que.push(v);
             rep(i,,){         //将v节点所维护的26个字母的最大数量更新
                 if(i!=str[v]-'a'){
                     dp[v][i]=max(dp[v][i],dp[u][i]);   //v点能够对其str[v]的字母数量做出1的贡献,所以这里分情况讨论一下
                 });
             }//维护经过v点的所有路径中所有字母的最大数量
         }
     }
     if(num<n)return false;     //如果存在环,直接输出NO
     return true;
 }
 int main(){
     read(n);read(m);
     init();
     scanf();
     rep(i,,m){
         int u,v;read(u);read(v);
         addedge(u,v);
         deg[v]++;     //记录每个点的入度
     }
     rep(i,,n) if(!deg[i]){
             que.push(i);         //将入度为0的加入队列
             dp[i][str[i]-'a']++; //初始化每个0入度点,刚开始维护的字母种类对应的数量
     }
     if(!topo())puts("-1");
     else {
         ;
         rep(i,,n) rep(j,,){
             ans=max(ans,dp[i][j]);
         }
         printf("%d\n",ans);
     }
 }

2019-02-16

上一篇:【转】python删除文件里包含关键词的行


下一篇:Discuz网警过滤关键词库