樹形DP(放置街燈,uva 10859)

2021-07-24 06:05:48 字數 1377 閱讀 3758

前面也做了一道很像的題,那道題只要求放置的數目最少,要求覆蓋的是點。在這題中,要求覆蓋的是邊,不但要求放著的數目最少,更要求覆蓋兩次的邊最多。因此貪心法不再適用,最少要多少個點可以貪心求出,但是同時要求覆蓋兩次的邊要最多卻不是貪心法能夠解決的,無論如何都是逃不過動態規劃的。所以一開始用貪心做,做到最後發現方法是錯的。看了大白書才開始用動態規劃。

大白書上的方法好奇怪,dp[i][j]代表i節點的父親節點是否放燈。好難理解。我用dp[i][j]代表i節點是否放燈思路十分清晰,很快就ac了。看了好久書才理解大白書上的做法,感覺不是很好。

大白書上最值得學習的地方就是如何定義動態規劃的值。

本題的優化目標有兩個,乙個是要求燈數a應盡量少,另乙個是要求被兩盞燈同時照亮的邊數b應盡量大。如果燈數盡量少,那麼就不會出現一條邊被照亮3次的低效情況,因此總邊數=被照亮1次的邊數+被照亮2次的邊數。即m=b+c。我們要求b盡量大,那麼要求c盡量小即可。這樣就把兩個優化目標都轉化成了盡量小。題目要求在a盡量小的前提下c盡量小,有個技巧是將二者組合成乙個量am+c,m是乙個比(c的最大理論值-c的最小理論值)還要大的數,這樣當am+c最小時,一定是先保證了a最小,再保證c最小。在本題中m取2000。

我的方法:

若u不放燈,那麼值就是所有(子節點v放燈的值+1)的和。+1是因為uv之間只被照亮1次。

若u放燈,那麼所以子節點愛放不放,如果不放,就要+1,然後取最小值求和就好了。

設根為root,答案就是min(dp[root][0],dp[root][1])。

思路又清晰,編碼又簡單,自己覺得比書上好多了。

我的方法

#include#define maxn 1010

#define max 2000

using namespace std;

int n,m;

vectormap[maxn];

int dp[maxn][2];

bool vis[maxn];

void dfs(int u,int f)

{ vis[u]=true;

dp[u][0]=0;

dp[u][1]=max;

for(unsigned int i=0;i

#include#define maxn 1010

#define max 2000

using namespace std;

int n,m;

vectormap[maxn];

bool vis[maxn];

int dp[maxn][2];

void dfs(int u,int f)

{ vis[u]=true;

int jc1,jc2;

jc1=jc2=0;

for(unsigned int i=0;i

放置街燈(UVA 10859)

問題描述 給你乙個n個點m條邊的無向無環圖,在盡量少的節點上放燈,使得所有燈都被照亮。每盞燈將照亮以它為乙個端點的所有邊。在燈的總數最小的前提下,被兩盞燈同時照亮的邊數應盡量大。輸入格式 輸入的第一行為測試資料組數t t 30 每組資料第一行為兩個整數n和m m n 1000 即點數 所有點編號為0...

uva1292 基礎樹形dp

思路 題目的意思是,遊一棵樹或者是森林,然後要在某些節點上放置乙個警察來防衛,然後每個警察呢只能防衛到自己所在節點和相鄰的節點,求所有節點都在直接或間接被防衛的時候需要的最少警察數目。意思顯然,然後就是dp了 對於當前節點的決策是選與不選,dp i j 表示第i個節點的是否直接放置警察 初始化是dp...

BZOJ2314 士兵的放置 樹形DP

八中有n個房間和n 1雙向通道,任意兩個房間均可到達.現在出了一件極bt的事,就是八中開始鬧鬼了。老大決定加強安保,現在如果在某個房間中放乙個士兵,則這個房間以及所有與這個房間相連的房間都會被控制.現在 老大想知道至少要多少士兵可以控制所有房間.以及有多少種不同的方案數.第一行乙個數字n,代表有n個...