1. 程式人生 > >Perfect service(樹形dp)

Perfect service(樹形dp)

sin space cst ice return 服務器 scan con 表示

Perfect service(樹形dp)

有n臺機器形成樹狀結構,要求在其中一些機器上安裝服務器,使得每臺不是服務器的計算機恰好和一臺服務器計算機相鄰。求服務器的最小數量。n<=10000。

這種類似獨立集的樹形dp問題,都可以將同一個結點的狀態分成幾類。這裏用\(f[i][0]\)表示i是服務器,\(f[i][1]\)表示i不是服務器,但是i的父親是服務器。\(f[i][2]\)表示i和i的父親都不是服務器。

那麽就可以寫出轉移方程:\(f[i][0]=sum(min(f[v][0], f[v][1]))+1\)\(f[i][1]=sum(f[v][2])\)\(f[i][2]=min(f[i][1]-f[v][2]+f[v][0])\)

。時間復雜度為\(O(n)\)

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

const int maxn=1e4+5;

int cntedge, fir[maxn];
struct Edge{
    int to, next;
}e[maxn];
void RESET(){ cntedge=0; memset(fir, 0, sizeof(fir)); }
void addedge(int x, int y){
    Edge &e1=e[++cntedge];
    e1.to=y; e1.next=fir[x]; fir[x]=cntedge;
}

int
n, f[maxn][3]; //0:自己是 1:父親是 2:自己和父親都不是 //也可以保存訪問順序,在外部訪問 void dfs(int u, int par){ f[u][0]=1; f[u][1]=0; f[u][2]=n; int v; for (int i=fir[u]; i; i=e[i].next){ if ((v=e[i].to)==par) continue; dfs(v, u); f[u][0]+=min(f[v][0], f[v][1]); f[u][1]+=f[v][2]; } for
(int i=fir[u]; i; i=e[i].next){ if ((v=e[i].to)==par) continue; f[u][2]=min(f[u][2], f[u][1]-f[v][2]+f[v][0]); } } int main(){ int t1=0, t2; while (~t1&&~scanf("%d", &n)){ RESET(); for (int i=1; i<n; ++i){ scanf("%d%d", &t1, &t2); addedge(t1, t2); addedge(t2, t1); } dfs(1, 0); printf("%d\n", min(min(f[1][0], f[1][1]), f[1][2])); scanf("%d", &t1); } return 0; }

Perfect service(樹形dp)