链接:http://codeforces.com/problemset/problem/919/D
题意: 每个节点有个颜色,现在有n 个节点和m条边,现在要找出一条路径使得走过的点的颜色相同的数量最大。输出数量。可能出现环或者平行边。如果答案为inf 输出-1。
思路: 每个节点只受其后边节点(拓扑)的影响,意思是我如果能够确定该节点后边所有节点的状态,那么这个节点肯定也是能确定的,并且满足没有后效性。,所以我可以对每个节点只搜一遍,如果下次搜到这个节点就直接返回。这样就会很快了。当然要先确定有没有-1的情况,既拓扑一下,如果有一个点并没有被拓扑到,那么肯定是有-1的情况。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N =3e5+5;
int n,m;
char s[N];
int flag[N];
int vis[N];
int num[N];
int inde[N];
int tmp[N];
vector< int >ve[N];
int res;
int Ans;
int dp[N][30];
void dfs(int u)
{
if(vis[u]!=-1) return ;
if(ve[u].size()==0){
dp[u][num[u]]++;
vis[u]=1;
return ;
}
for(int i=0;i<ve[u].size();i++){
int v=ve[u][i];
dfs(v);
for(int j=1;j<=26;j++){
if(j==num[u]){
dp[u][j]=max(dp[u][j],dp[v][j]+1);
}
else dp[u][j]=max(dp[u][j],dp[v][j]);
}
}
vis[u]=1;
return ;
}
int main()
{
scanf("%d %d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=n;i++){
num[i]=s[i]-'a'+1;
}
int u,v;
for(int i=1;i<=m;i++){
scanf("%d %d",&u,&v);
ve[u].push_back(v);
inde[v]++;
tmp[v]++;
}
queue<int >q;
int cnt=0;
for(int i=1;i<=n;i++){
if(inde[i]==0){
q.push(i);
vis[i]=1;
cnt++;
}
}
while(!q.empty()){
u=q.front(); q.pop();
for(int i=0;i<ve[u].size();i++){
int v=ve[u][i];
tmp[v]--;
if(tmp[v]==0){
vis[v]=1;
q.push(v);
cnt++;
}
}
}
if(cnt!=n){
printf("-1\n");
return 0;
}
memset(vis,-1,sizeof(vis));
for(int i=1;i<=n;i++){
for(int j=1;j<=26;j++){
dp[i][j]=0;
}
}
for(int i=1;i<=n;i++){
if(inde[i]==0){
dfs(i);
for(int j=1;j<=26;j++){
Ans=max(Ans,dp[i][j]);
}
}
}
printf("%d\n",Ans);
return 0;
}