<题目链接>
题目大意:
有一个具有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