題意:給你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 這個題其實挺簡單的,但是我是真的廢。題意 給出一棵樹,每個節點有自己的權值,選擇出一些點,選擇點的時候如果選...