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