【題解】 樹形dp 守衛部署

當我又是水一發博客
題解的意義不在於題解,主要這次可能是很鬱悶的一次掛在裸題上…


題目

問題描述

徵夷王(徵夷大白兔王子青王神人)最近打算滅掉越南(南夷)。徵夷王的國家由N個城市、N-1條雙向道路組成,其中,任意兩個城市之間有且僅有一條通路連接。
然而,萬惡的日本(東倭)想在此時偷襲徵夷王的國家!
每當一個城市被襲擊時,與之有直接道路相連的城市或該城市中若有一隻守衛軍隊,便可以化險爲夷。但是,如果與之有直接道路相連的城市和該城市中沒有一個城市有一隻守衛軍隊,那麼這個城市就悲劇了。徵夷王顯然不願意看到自己的國家侵略。所以他在某些城市部署若干只守衛軍隊,使得任意一個城市被襲擊時均可化險爲夷。但是,爲了儘可能迅捷地滅掉南夷,徵夷王希望部署的守衛軍隊只數最少。現在偉大的王想知道,他最少要部署多少隻守衛軍隊?

輸入

輸入文件名爲Guard.in。
輸入第一行一個正整數N,代表徵夷王國家擁有的城市個數。
下接N-1行,每行兩個正整數Xi和Yi,表示編號爲XI和YI的城市之間有一條雙向道路。

輸出

輸出文件名爲Guard.out。
輸出第一行一個正整數,代表最少要部署的軍隊個數。

輸入輸出樣例

Guard.in Guard.out
5 2
1 3
5 2
4 3
3 5

數據範圍

30%的數據,1<=N<=10。
100%的數據,1<=N<=100000。


題解

顯然裸題,類似警衛安排設置狀態
需要注意的是,不要多叉轉二叉!,耗時太多,直接利用鄰接表建多叉樹即可
血與淚的教訓,可看註釋


代碼

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int maxn = 2 * (1e5 + 10);
int head[maxn], nxt[maxn], pot[maxn], fa[maxn], cnt = 0;
//int bro[maxn], son[maxn];
inline void Line (int x, int y){
    nxt[++cnt] = head[x], pot[cnt] = y, head[x] = cnt;
    nxt[++cnt] = head[y], pot[cnt] = x, head[y] = cnt;
}
/*bool book[maxn] = {0};
queue<int> q;
void build(int U){
    int u, v, fs; q.push(U);
    while (!q.empty()){
    u = q.front(); q.pop();
    for (int i = head[u]; i; i = nxt[i]){
        v = pot[i];
        if (!book[v]){
        if (!son[u]) son[u] = v;
        else bro[fs] = v;
        q.push(v); fs = v;
        }
    }
    book[u] = 1;
    }
    }*/
void getfa(int rt){
    for (int i = head[rt]; i; i = nxt[i])
    if (pot[i] != fa[rt]) fa[pot[i]] = rt, getfa(pot[i]);
}
int inf = 0x3f3f3f3f, f[maxn][3]; //self, son, father
inline int Min (int a, int b){return a < b ? a : b;}
int dp(int rt, int s){
    if (!rt) return inf;
    if (f[rt][s] >= 0) return f[rt][s];
    int mn, v, sum = 0;
    //v = son[rt];
    //while (v){sum += Min(dp(v, 0), dp(v, 1)); v = bro[v];}
    for (int i = head[rt]; i; i = nxt[i]){
    if ((v = pot[i]) == fa[rt]) continue;
    sum += Min(dp(v, 0), dp(v, 1));
    }
    if (!s){
    f[rt][s] = 1;
    //v = son[rt];
    //while (v){f[rt][s] += Min(f[v][0], Min(f[v][1], dp(v, 2))); v = bro[v];}
    for (int i = head[rt]; i; i = nxt[i]){
        if ((v = pot[i]) == fa[rt]) continue;
        f[rt][s] += Min(f[v][0], Min(f[v][1], dp(v, 2)));
    }
    return f[rt][s];
    }
    if(s == 1){
    //v = son[rt];
    mn = inf;
    //while (v){mn = Min(mn, sum - Min(f[v][0], f[v][1]) + f[v][0]); v = bro[v];}
    for (int i = head[rt]; i; i = nxt[i]){
        if ((v = pot[i]) == fa[rt]) continue;
        mn = Min(mn, sum - Min(f[v][0], f[v][1]) + f[v][0]);
    }
    return f[rt][s] = mn;
    }
    return f[rt][s] = sum;
}
int main (){
    freopen ("guard.in", "r", stdin);
    freopen ("guard.out", "w", stdout);

    int n; scanf ("%d", &n);
    for (int i = 1, x, y; i < n; ++i){
    scanf ("%d%d", &x, &y);
    Line(x, y);
    }
    //build(1);
    getfa(1); memset(f, -1, sizeof f);
    printf ("%d", Min(dp(1, 0), dp(1, 1)));

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