Codeforces Round #460 (Div. 2)D. Substring(拓扑排序(DAG)+DP)or(记忆化搜索)

http://codeforces.com/contest/919/problem/D

题意:给你一个字符串与有向图(字符串下标与有向图点相对应),让我们求某一路径上相同字符个数最大为多少?若存在环,则输出-1。

这道题有两种方法来做;dp[i][j]表示i点为起点j字母的字符个数.

第一种,用拓扑排序的思想+DP,

拓扑排序的起点与终点要互换(在存储在vector里面的时候,反向求解)

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
int n,m;
int vis[maxn];
int into[maxn];
char s[maxn];
int num[maxn];
int dp[maxn][30];
vector<int>v[maxn];
int ring(int x)
{
    if(vis[x]==1)
        return 1;
    if(vis[x]==2)
        return 0;
    vis[x]=1;
    int ss=v[x].size();
    for(int i=0;i<ss;i++)
    {
        int y=v[x][i];
        if(ring(y))
            return 1;
    }
    vis[x]=2;
    return 0;
}
int main()
{
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        memset(vis,0,sizeof(vis));
        memset(into,0,sizeof(into));
        memset(dp,0,sizeof(dp));
        scanf("%s",s);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            v[y].push_back(x);
            into[x]++;
        }
        for(int i=0;i<n;i++)
        {
            num[i+1]=(int)(s[i]-'a');
        }
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&ring(i))
            {
                printf("-1\n");
                flag=1;
                break;
            }
        }
        if(flag) continue;
        queue<int>q;
        for(int i=1;i<=n;i++)
            if(into[i]==0)
                q.push(i);
        int cnt=0;
        while(q.size())
        {
            int x=q.front();
            q.pop();
            into[x]--;
            int ss=v[x].size();
            dp[x][num[x]]++;
            cnt=max(cnt,dp[x][num[x]]);
            for(int i=0;i<ss;i++)
            {
                int y=v[x][i];
                into[y]--;
                if(into[y]==0)
                    q.push(y);
                for(int j=0;j<26;j++)
                {
                    dp[y][j]=max(dp[y][j],dp[x][j]);
                    cnt=max(cnt,dp[y][j]);
                }

            }

        }
        printf("%d\n",cnt);
    }

    return 0;
}
拓扑排序

第二种,用记忆化搜索DP;

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 ///exit(0)函数正常退出
 4 const int maxn=3e5+10;
 5 int n,m;
 6 int num[maxn];
 7 int dp[maxn][30];
 8 string s;
 9 vector<int>v[maxn];
10 int dfs(int pos,int val)
11 {
12     if(dp[pos][val]==-2)
13     {
14         printf("-1\n");
15         exit(0);
16     }
17     if(dp[pos][val]!=-1)
18         return dp[pos][val];
19 
20     int ss=v[pos].size();
21     dp[pos][val]=-2;
22     int cnt=0;
23     for(int i=0;i<ss;i++)
24     {
25         int y=v[pos][i];
26         cnt=max(cnt,dfs(y,val));
27     }
28     if(val==num[pos])
29         cnt++;
30     dp[pos][val]=cnt;
31     return cnt;
32 }
33 int main()
34 {
35     while(scanf("%d %d",&n,&m)!=EOF)
36     {
37         cin>>s;
38         memset(dp,-1,sizeof(dp));
39         for(int i=0;i<n;i++)
40             num[i+1]=s[i]-'a';
41         for(int i=1;i<=m;i++)
42         {
43             int x,y;
44             scanf("%d %d",&x,&y);
45             v[x].push_back(y);
46         }
47         int ans=0;
48         for(int i=1;i<=n;i++)
49             for(int j=0;j<26;j++)
50                 ans=max(ans,dfs(i,j));
51         printf("%d\n",ans);
52     }
53     return 0;
54 }
记忆化搜索

刚开始写博客,很多东西都还是才开始学习。

想着写方法培训的时候都是学习了得,但是在比赛的时候自己根本就没有朝这方面想的思路,

比赛的时候完全没什么思路,都不知道该怎么做,可能这就是题练少了,对这方面的知识也欠缺的表现吧!~~

这些东西都是在比赛完之后借鉴了许多大牛的博客自己慢慢一点点的弄懂的东西。

加油吧!~!

posted @ 2018-03-04 15:32  孟加拉国  阅读(170)  评论(0编辑  收藏  举报