CF 1029E Tree with Small Distances 樹形DP or 貪心

Ghostkkkk發表於2018-09-05

題意:

給你一顆樹,問你要使1號節點到所有節點的距離不超過2,最少新增多少邊?

題解:

顯然新增的邊肯定連1好。

利用樹形DP。

我們設dp[i][j]為i號節點到1的距離為j,並且i號節點的子樹都滿足要求的最少邊數。

這樣dp[n][2]即可,

dp[i][1] = (i == 1 || par == 1 ? 0 : 1)

但是dp[i][2]有兩種情況,一種是i節點經過父親再到1的距離為2, 一種是經過子節點再到1的距離為2。

這兩種情況的DP方程不同,我們把dp[i][2]拆成兩種狀態,dp[i][2]表示經過父親再到1,dp[i][3]表示經過子節點再到1。

dp[i][2]  = \summin(dp[v][1], dp[v][3])

dp[i][3] = dp[i][2] + max( min(dp[i][1] - dp[i][3]), 0)

初始狀態,對於葉子節點i:

dp[i][1] = dp[i][1] = (i == 1 || par == 1 ? 0 : 1)

dp[i][2] = 0. 

dp[i][3] = INF

程式碼:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <cmath>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif

#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pii;

const ll MOD = 1e9 + 7;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 2e5 + 5;

int d[MAXN][4];
vector<int> G[MAXN];


void dfs (int now, int par) {
    d[now][1] = (now == 1 || par == 1 ? 0 : 1);
    int minn = INF;
    for(int i : G[now]) {
        if(i == par) continue;
        dfs(i, now);
        d[now][1] += min(d[i][1], d[i][2]);
        d[now][2] += min(d[i][1], d[i][3]);
        minn = min(d[i][1] - d[i][3], minn);
    }
    d[now][3] = d[now][2] + max(minn, 0);
}


int main() {
#ifdef LOCAL
    freopen ("input.txt", "r", stdin);
#endif
    int n;
    cin >> n;
    for (int i = 2; i <= n; i++) {
        int x, y;
        scanf ("%d %d", &x, &y);
        G[x].pb (y);
        G[y].pb (x);
    }
    dfs(1, 0);
    int ans = 0;
    for(int i : G[1]) ans += d[i][1];
    printf("%d\n", ans);
    return 0;
}

 

相關文章