【洛谷】P1137 旅行計劃

【洛谷】P1137 旅行計劃


0.總結

Get to the points first. The article comes from LawsonAbs!
  • 樹形dp問題的處理
  • 拓撲排序

1.題意

其實就是求一棵樹裏各個節點的子節點個數。

2.分析

如果單純的使用dfs+dp的方法那麼在面對多叉的情況下就會失效。其原因是:會包含重複的節點【用術語來說就是,一個節點有不止一個父節點】。那麼該怎麼解決這個問題呢? 可以化樹形序列爲dp序列,然後在得到線型序列【放到數組裏】的基礎上進行dp計算。
主要步驟如下:

  • 按照由西到東【或者由東到西也是可以的,建圖什麼順序,就決定了後面的dp該以什麼順序更新值】進行一個建圖的操作
  • 將樹形結構進行一個拓撲排序,將排序的結果放到一個數組 topo[] 中,並按照得到的順序
  • 將上面得到的 topo[] 結構進行一個dp計算,取子節點中的最大值

3.代碼

3.1 錯誤代碼

下面這份代碼,則是

// Created by lawson on 20-6-16.
#include<iostream>
using namespace std;
const int maxM = 200005;
const int maxN = 100005;

//head[i]表示節點i 指向的第一個節點
//next[i] 表示第i條辺的開始節點
int head[maxM],nex[maxM],to[maxM];
int n,m,cnt = 0;//cnt 表示辺的個數
int ro[maxN];
int dp[maxN];//dp[i]表示節點i能夠遊覽最多的城市數


//添加辺的過程 a->b
void add(int a,int b){
    nex[cnt] = head[a];
    to[cnt] = b;//第cnt條辺指向的終點
    head[a] = cnt; //節點a指向的第一條邊的下標
    cnt++;
}

/*
01.如果不先拓撲排序,那麼對於一個分叉的節點就無法得到正確答案
 */
//當前節點cur
void dfs(int cur){
    int y;//目的節點
    for(int i = head[cur];i!=-1;i = nex[i]){ //這裏遍歷得到的i是辺的序號
        y = to[i];
        dfs(y);//繼續往下遍歷
        dp[cur] = max(dp[cur],dp[y]);
    }
    dp[cur]+=1;//加上自己的一個節點
}


int main(){
    cin >> n >> m;
    int l,r;//左右兩個節點。 l在r的西面
    fill(head,head+maxM,-1);//以-1結尾
    for(int i = 0;i< m;i++){
        cin >> l >> r;
        ro[l] = 1;
        add(r,l);//反着加
    }
    for(int i = 1;i<=n;i++){
        if(!ro[i]) //如果該點是
            dfs(i);
    }
    for(int i = 1;i<=n;i++)
        cout << dp[i]<<"\n";
    return 0;
}

3.2 ac代碼

待補坑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章