Longest Path

题目大意

这个是一个有向无环图,
image
然后求最长的那个路径,

错误解法

void solve() {
  int n,m,rec=INT_MIN;cin>>n>>m;
  vector<int>dp(n+1);
  while(m--){
    int x,y;cin>>x>>y;
    dp[y]=max(dp[y],dp[x]+1);
    rec=max(dp[y],rec);
  }
  cout<<rec<<endl;

似乎把问题想的太简单了

错误原因

3 2
2 3
1 2
1->2->3,应该是3
但是你的写法会让答案是1,但是正确答案是2

因为你在处理2的时候,2是0,但是后面会跟3连,这个时候2又变成1了,但是1没有被记录进去
究其原因就是,题目不一定都是按照拓扑序拍好的,
什么叫拓扑序?拓扑序(Topological Order),简单来说,就是“按先后依赖关系排好的一条直线顺序”
有向无环图才有拓扑序,是才有,不是一定有
题目给的例子你都能过,因为题目的例子都非常阴间的按照拓扑序排好的

正确解法1 DFS

const int MAXN = 100005;
vector<int> adj[MAXN];
int dp[MAXN]; // dp[u] 表示从 u 出发的最长路径
int dfs(int u){
    if(dp[u]!=-1)return dp[u];
    int rec=0;
    for(int v:adj[u]){
        rec=max(rec,dfs(v)+1);
    }
    return dp[u]=rec;
}
void solve(){
    int n,m;
    cin>>n>>m;
    while(m--){
        int x,y;
        cin>>x>>y;
        adj[x].pb(y);
    }
    memset(dp,-1,sizeof(dp));
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,dfs(i));
    }
    cout<<ans<<endl;
}

解释

枚举每一个点,看从哪一个点出发的距离是最大的

正确解法2 拓扑序+dp

//拓扑排序 + DP(Kahn 算法)
void solve2(){
    int n,m;cin>>n>>m;
    vector<int>dp(n+1);
    vector<int>in_degree(n+1);
    vector<vector<int>>adj(n+1);
    queue<int>q;
    int ans=0;
    while(m--){
        int x,y;cin>>x>>y;
        adj[x].pb(y);
        in_degree[y]++;//记录它的前驱,如果没有前驱就是直接进入queue
        /*
        这个就对应了这个例子
        2 3
        1 2
        只有当2没有前驱的时候,才可以入队列,
        才可以有dp[3]=max(dp[3],dp[2]+1) 
        */
    }
    for(int i=1;i<=n;i++){
        if(in_degree[i]==0){
            q.push(i);
        }
    }
    while(!q.empty()){
        int kk=q.front();
        ans=max(ans,dp[kk]);//记录全局的最大值
        q.pop();
        for(int v:adj[kk]){
            dp[v]=max(dp[v],dp[kk]+1);
            in_degree[v]--;//如果这条边没来,它的度就为0了,说明没有前驱了,就可以进入队列了
            if(in_degree[v]==0)q.push(v);
        }
    }
    cout<<ans<<endl;
}

解释,就如上面那个例子,只有2没有前驱的时候,才可以方向的进行

dp[3]=max(dp[3],dp[2]+1),我们维护一个队列,这个队列记录的就是那些没有前驱的点

posted @ 2026-03-10 21:48  Time_q  阅读(5)  评论(0)    收藏  举报