1. 程式人生 > >CodeForces 219D.Choosing Capital for Treeland (樹形dp)

CodeForces 219D.Choosing Capital for Treeland (樹形dp)

out sizeof else logs getc 如果 tail tin 所有

題目鏈接:

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

題意:

給一個n節點的有向無環圖,要找一個這樣的點:該點到其它n-1要逆轉的道路最少,(邊<u,v>,如果v要到u去,則要逆轉該邊方向)如果有多個這樣的點,則升序輸出所有

思路:

看了三篇博客,挺好的

http://blog.csdn.net/chl_3205/article/details/9284747

http://m.blog.csdn.net/qq_32570675/article/details/53691814 一遍dfs

http://blog.csdn.net/angon823/article/details/52316220

正向邊權值為0,反向為1.

第一次dfs記錄每個點到所有子樹中需要改變的邊的條數。 (自下向上推)(優化下只需求出根節點到所有的點需要改變的邊的條數)

第二次dfs由父節點求子節點到所有點的需要改變的邊的條數。(自上向下)

把邊的方向化為權值,正向為1,逆向為0。

問題轉化為找哪些點的在遍歷全圖後總權值最大。

這就是樹形DP了,考慮每個節點,它可以從子樹收獲價值,也可以從父親收獲。所以dfs兩遍,一邊把子樹的價值存到dps[i]裏,再一遍把父親的價值存到dpf[i]裏。ans[i] = dps[i] + dpf[i]。這都是老套路了!

技術分享

對於陰影那個點,第一遍dfs求出所有以下子節點(子樹)對他的貢獻,那麽只有那根紅線沒有計算,第二遍dfs是計算父親對他的貢獻

代碼:

代碼一:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<0||ch>
9){if(ch==-)f=-1;ch=getchar();} while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} return x*f; } ////////////////////////////////////////////////////////////////////////// const int maxn = 2e5+10; int n,res,dp[maxn]; bool vis[maxn]; vector<pair<int,int> > g[maxn]; void dfs1(int u){ vis[u] = 1; for(int i=0; i<(int)g[u].size(); i++){ int v = g[u][i].first; if(vis[v]) continue; dfs1(v); res += g[u][i].second; } } void dfs2(int u){ vis[u] = 1; for(int i=0; i<(int)g[u].size(); i++){ int v = g[u][i].first, w = g[u][i].second; if(vis[v]) continue; if(w) dp[v] = dp[u]-1; else dp[v] = dp[u]+1; dfs2(v); } } int main(){ cin >> n; for(int i=1; i<n; i++){ int u,v; scanf("%d%d",&u,&v); g[u].push_back(MP(v,0)); g[v].push_back(MP(u,1)); } dfs1(1); dp[1] = res; MS(vis); dfs2(1); int mi = INF, last; for(int i=1; i<=n; i++) if(dp[i] <= mi) mi = dp[i]; cout << mi << endl; for(int i=1; i<=n; i++){ if(dp[i] == mi){ cout << i << " "; } } puts(""); return 0; }

代碼二:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 1e6+10;

int n,dps[maxn],dpf[maxn];
vector<pair<int,int> > g[maxn];

void dfs1(int u,int fa){
    for(int i=0; i<(int)g[u].size(); i++){
        int v = g[u][i].first, w = g[u][i].second;
        if(v == fa) continue;
        dfs1(v,u);
        dps[u] += w;
        dps[u] += dps[v];
    }
}

void dfs2(int u,int fa){
    for(int i=0; i<(int)g[u].size(); i++){
        int v = g[u][i].first, w = g[u][i].second;
        if(v == fa) continue;
        dpf[v] = dpf[u]+dps[u]-dps[v]-w + (w?0:1);
        dfs2(v,u);
    }
}

int main(){
    cin >> n;
    for(int i=1; i<n; i++){
        int u,v; scanf("%d%d",&u,&v);
        g[u].push_back(MP(v,0));
        g[v].push_back(MP(u,1));
    }

    dfs1(1,-1);
    dfs2(1,-1);

    int mi = INF;
    for(int i=1; i<=n; i++)
        mi = min(mi,dps[i]+dpf[i]);
    cout << mi << endl;
    for(int i=1; i<=n; i++)
        if(dps[i]+dpf[i] == mi)
            cout << i << " ";
    puts("");

    return 0;
}

CodeForces 219D.Choosing Capital for Treeland (樹形dp)