樹形DP POJ3659 好難的一道題

2021-08-01 05:49:36 字數 1537 閱讀 3498

題意:給你n個點,給出n-1無向邊表示這兩個點相鄰,問最小選幾個點可以把整個區域覆蓋(乙個點被選會覆蓋它相連的節點)

思路:可以隨機把乙個點看做根節點成為乙個樹,然後做樹上dp

1我們定義:

dp[i][0]:自己被選,且所有子節點被覆蓋的最小值

dp[i][1]:自己不被選,被父親節點覆蓋,且所有子節點被覆蓋的最小值;

dp[i][2]:自己不被選,不被父親節點覆蓋,且所有子節點被覆蓋的最小值

2初始化:

dp[i][0]=1; dp[i][1]=0;  如果i是葉子節點dp[i][2]=inf 否則dp[i][2]=0; 

3設i的任意乙個兒子的標號為u,有轉移方程

(1).如果當前節點被選,那麼子節點可以取任何情況,累計每個子節點三中情況的最小值

dp[i][0]+=min(dp[u][0],dp[u][1],dp[u][2] ); 

(2).如果當前節點被父親節點覆蓋且沒被選,那麼子節點可以是自己被選,或者不被選不被父親覆蓋的最小值。

dp[i][1]+=min(dp[u][0],dp[u][2] );

(3).如果當前節點沒有被兒子覆蓋且沒被選,和上一種情況基本相似,

注意:必須有乙個兒子被選,如果沒被選當前節點就沒有被覆蓋!!!

所以我們在取最小值的時候要記錄一下是否取到兒子被選的情況,同事維護乙個最小值(dp[u][0]-dp[2]);

如果沒有取到兒子被選的情況 那麼dp[i][2]+=min;需要補上乙個最小值,使最小值的那個子節點被選!!!

具體的操作見**,上面還有一些細節!!!

#include #include#include#includeusing namespace std;

const int maxn=10100;

const int inf=999999;

struct node

edge[maxn<<1];

int head[maxn];

int cnt=0;

void add(int u,int v)

int n;

int dp[maxn<<1][3];

//dp[i][0] 自己被選

//dp[i][1] 自己沒被選,父親被選包含了他

//dp[i][2] 自己沒被選,父親沒選沒包含他他,兒子包含了他

bool vis[maxn<<1];

void dfs(int root)

int m=inf;

bool flag=1;

for(int i=head[root];i!=-1 ;i=edge[i].next)

else}}

if(flag) dp[root][2]+=m;

}int main()

{ scanf("%d",&n);

memset(head,-1,sizeof(head));

memset(vis,0,sizeof(vis));

cnt=0;

for(int i=1;i

poj 3659 樹形dp(樹上的最小支配集)

題意 求樹的最小支配集。思路 動態規劃。一開始每個點只取了兩個變數,表示在以其為根的子樹中選擇和不選擇該點的最少點數。由一組資料 6個點的路徑 發現了問題,考慮第3個點的時候,如果不選擇此點,那麼第4個點必須要選取,實際上這是不必的。該組資料的最優解是選擇第2和第5個點。dp1 x 表示選擇第x個點...

JavaScript之樹形結構的資料 一

在前端js程式設計中,經常需要在前端頁面顯示組織機構之類的樹形結構資料,下面的 可以組成乙個樹形結構的資料。現成的樹形結構資料如下 const data const device const alarminput function tree parent,children o.key parent ...

樹形dp 的 一道巨簡單題

這三個字寫這麼大完全是為了提醒自己 hhhh 竟然這都不會 樹形dp 不懂得如何推出狀態表示式 即使再簡單 看見題目就無從下手!有點煩 所以決定多刷一點dp題,先看了最基礎的 洛谷p1352 這個題其實挺簡單的,但是我是真的廢。題意 給出一棵樹,每個節點有自己的權值,選擇出一些點,選擇點的時候如果選...