zoukankan      html  css  js  c++  java
  • Codeforces 919D Substring ( 拓扑排序 && DAG上的DP )

    题意 : 给出含有 N 个点 M 条边的图(可能不连通或者包含环),每个点都标有一个小写字母编号,然后问你有没有一条路径使得路径上重复字母个数最多的次数是多少次,例如图上有条路径的顶点标号顺序是  abcaca 那么答案就是 3 ,因为 a 出现了三次,如果答案无穷大则输出 -1

    分析 : 

    不难联想到是一个动态规划类型的题目

    定义 DP[i][j] 为到达顶点 i 时字母 j 最多出现了多少次

    显然如果图中有环的话就输出 -1

    这也就是说如果图中不存在合法拓扑排序就说明有环

    如果存在拓扑排序,那么就是一个DAG

    我们可以构造出拓扑序列,然后在这个图上进行上述DP过程

    状态转移方程为 dp[ i 出度顶点 ][j] = max{ dp[ i 出度顶点][j], dp[i][j] + (i 出度顶点编号 == j ? 1 : 0) }

    可以使用队列构造拓扑排序,在构造的过程中完成 DP

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 3e5 + 10;
    struct EDGE{ int v, nxt; }Edge[maxn];
    char ch[maxn];
    int Deg[maxn];
    int dp[maxn][26];
    int Head[maxn], cnt;
    int N, M;
    
    inline void init()
    {
        for(int i=0; i<=N; i++){
            Head[i] = -1, Deg[i] = 0;
            for(int j=0; j<26; j++)
                dp[i][j] = 0;
        }
        cnt = 0;
    }
    
    inline void AddEdge(int From, int To)
    {
        Edge[cnt].v = To;
        Edge[cnt].nxt = Head[From];
        Head[From] = cnt++;
    }
    
    #define Debug 0
    int main(void)
    {
    #if Debug
        freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
    #endif // Debug
        while(~scanf("%d %d", &N, &M)){
            for(int i=1; i<=N; i++)
                scanf(" %c", &ch[i]);
    //        for(int i=1; i<=N; i++)
    //            putchar(ch[i]);
            init();
            int From, To;
            while(M--){
                scanf("%d %d", &From, &To);
                AddEdge(From, To);
                Deg[To]++;
            }
    
            queue<int> que;
            while(!que.empty()) que.pop();
            for(int i=1; i<=N; i++)
                if(!Deg[i]){
                    que.push(i);
                    dp[i][ch[i]-'a'] = 1;
                }
    
            int num = 0;
            while(!que.empty()){
                int v = que.front();
                que.pop();
                num++;
                for(int i=Head[v]; i!=-1; i=Edge[i].nxt){
                    int Eiv = Edge[i].v;
                    for(int j=0; j<26; j++)
                        dp[Eiv][j] = max(dp[Eiv][j], dp[v][j] + (ch[Eiv]-'a' == j));
                    Deg[Eiv]--;
                    if(!Deg[Eiv])
                        que.push(Eiv);
                }
            }
            //printf("%d
    ", num);
            if(num != N){
                puts("-1");
                continue;
            }else{
                int ans = 0;
                for(int i=1; i<=N; i++){
                    for(int j=0; j<26; j++){
                        ans = max(ans, dp[i][j]);
                    }
                }
                printf("%d
    ", ans);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    input框限制只能输入正整数、字母、小数、
    css水平垂直居中
    Android开发之旅-获取地理位置的经度和纬度
    Android DDMS应用
    Android开发BUG及解决方法2
    Android开发BUG及解决方法1
    Android开发BUG及解决方法
    Android系统架构
    1.sql简介
    C语言笔试常考知识点
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/8432509.html
Copyright © 2011-2022 走看看