點此看題
0x01 樹形dp
我一開始想寫樹形dpdp
dp,結果寫不出來。
其實這道題dpdp
dp也是可以的,定義dp[
u][i
]dp[u][i]
dp[u][
i]為離u
uu最近的被標記點距離為i
ii,然後處理完子樹u
uu的最小花費。
轉移就不詳細講了,相信你自己能yyyy
yy(比如用一些奇技淫巧 )出來。
0x02 貪心
我們跑一遍這棵樹,在回溯的時候存下離它最近的標記點和最遠的未標記點,如果未標記點再回溯就不可能在被標記,那就在當前點標記它,這其實是一種」能拖就拖「的貪心方法,因為標記最上面的點能涉及到的範圍最廣,也就最優,時間複雜度只有o(n
)o(n)
o(n)
。
#include
#include
using
namespace std;
const
int maxn =
10005
;int
read()
int n,tot,ans,f[maxn]
;struct edgee[2
*maxn]
;struct node
;node dfs
(int u,
int fa)
if(max==2)
;}if(max+min<=2)
return node
;return node;}
intmain()
,f[i]
=tot;
e[++tot]
=edge
,f[j]
=tot;
} node t=
dfs(1,
0);if
(t.x) ans++
;printf
("%d\n"
,ans)
;}
點此看題
其實本題一看就是樹形dpdp
dp的題,可是狀態的不確定性實在太大了,普通的樹dpdp
dp根本做不了。
考慮每個葉節點對答案的影響,發現每個葉節點只對該點到根節點的路徑上的決策有直接影響,而因為我們的樹是乙個完全二叉數,且深度為n
nn,所以我們在樹dpdp
dp中暴枚每條鏈的所有可能只會消耗o(2
n−1)
o(2^)
o(2n−1
),這樣我們就把樹上非葉節點的狀態確定了。
然後我們考慮確定葉節點的狀態,把它放進dpdp
dp式中,定義f[i
][j]
f[i][j]
f[i][j
]為第i
ii個點的子樹內的葉節點有j
jj個點參軍,然後跑揹包即可,注意我們樹dpdp
dp時用了暴力列舉可能性,f
ff陣列要清零。
每一層算複雜度,可得o(n
22n−
4)
o(n2^)
o(n22n
−4)
#include
#include
using
namespace std;
const
int maxn =
1025
;int
read()
int n,m,max,vis[10]
,a[maxn][10
],b[maxn][10
],f[maxn]
[maxn]
;void
dfs(
int u,
int y)
for(
int k=
0;k<=
1;k++)}
intmain()
for(
int i=
1<1<1;i++
)dfs(1
,n);
for(
int i=
0;i<=m;i++
) max=
max(max,f[1]
[i])
;printf
("%d\n"
,max)
;}
2020藍橋杯訓練賽 二
1 9的數字可以組成3個3位數,設為 a,b,c,現在要求滿足如下關係 b 2 a c 3 a 請你寫出a的所有可能答案,數字間用空格分開,數字按公升序排列。注意 只提交a的值,嚴格按照格式要求輸出。列舉遍歷,滿足要求的a只會在123 333範圍內,只要檢查一下a情況下,b,c是否全部符合題意,這裡...
訓練 9 13 訓練賽
a.hdu 6230 乙個合法的子串 s 3n 2 滿足條件即1 2n 1 為以n為回文中心的回文串,n 3n 2為以2n 1為中心的回文串。故我們可以通過尋找回文中心對,來判斷相應合法子串的個數。利用manacher求出每個位置的最長回文半徑,則若i,j滿足條件 i j 則應有 p i geqsl...
訓練賽 詠歎
安師大附中訓練題目 給定乙個1到n的排列a,對其進行氣泡排序 counter 0 while a不是公升序的 counter counter 1 for i 1 to n 1 if a i a i 1 then swap a i a i 1 endifend forend while那麼經過幾輪排序...