分析:比較神奇的一道題.要把樹變成環肯定要先變成鏈,然後把鏈給拼接成環.接下來考慮乙個腦洞大開的樹形dp:設f[i][0]表示i不與父節點相連的鏈數,f[i][1]表示i與父節點相連的鏈數,先考慮怎麼轉移f[i][0],如果i不與父節點相連,那麼i肯定與兩個子節點相連,其它的子節點都不與父節點相連,而且要剪掉與父親節點的一條邊,所以f[i][0] = (σf[j][0]) - f[p][0] - f[q][0] + f[p][1] + f[q][1] - 1.f[i][1]也能很容易推導出來f[i][1] = (σf[j][0]) - f[p][0] + f[p][1].這兩個式子中的p,q使我們選出來與i組成鏈的子節點,為了使得f[i][0/1]最小,我們要選出使f[j][1] - f[j][0]最小的p,q,這個在列舉的時候掃一下就可以了.
最後是合併,乙個樹有n-1條邊,先不斷地刪邊,然後加邊,加到n-1條邊,最後再補一條邊形成乙個環,可以發現刪邊和加邊是對稱的,需要刪掉鏈-1條邊,那麼也需要加上鏈-1條邊,最後用一條邊形成乙個環就可以了.
樹形dp,考慮好鏈的種類和怎麼從子節點轉移,充分利用好加邊和刪邊的對稱性,就能a掉此題,最關鍵的還是狀態的表示,樹形dp可能會需要儲存不同的狀態,如果對於當前狀態推不下去了,就多加點狀態,直到可做為止.
#include #include#include
#include
using
namespace
std;
const
int inf = 0x7fffffff
;int n, head[100010], to[200010], nextt[200010], tot = 1, f[100010][2
];void add(int x, int
y)void dfs(int u, int
from
)
else
if (temp
min2 =temp;}}
if (son == 0
) f[u][
0] = f[u][1] = 1
;
if (son == 1
) f[u][
0] = f[u][1] =sum2;
else
if (son >= 2
)
}int
main()
dfs(
1, 0
); printf(
"%d\n
", f[1][0] * 2 - 1
);
return0;
}
清北學堂模擬賽d3t3 c
分析 一開始拿到這道題真的是無從下手,暴力都很難打出來.但是基本的方向還是要有的,題目問的是方案數,dp不行就考慮數學方法.接下來比較難想.其實對於每一行或者每一列,我們任意打亂順序其實對答案是沒有影響的.那麼我們按照高度從大到小對行和列進行排序,單獨考慮所有高度相等的行和列,組成了乙個l形,如果我...
清北學堂模擬賽d3t1 a
問題描述 你是能看到第一題的friends呢。hja 怎麼快速記單詞呢?也許把單詞分類再記單詞是個不錯的選擇。何大爺給出了一種分單詞的方法,何大爺認為兩個單詞是同一類的當這兩個單詞的各個字母的個數是一樣的,如dog和god。現在何大爺給了你 個單詞,問這裡總共有多少類單詞。輸入格式 第一行乙個整數n...
清北學堂模擬賽d6t3 反擊數
分析 顯然是一道數字dp題,不過需要一些奇怪的姿勢.常規的數字dp能統計出乙個區間內滿足條件的數的個數,可是我們要求第k個,怎麼辦呢?轉化為經典的二分問題,我們二分當前數的大小,看它是第幾大的,就可以了.顯然數字dp套上模板,再用上kmp的next陣列就可以了,傳遞4個引數 還剩下多少位沒有匹配,匹...