有n個點,n-1條邊的一棵樹,給出它的每條邊x,y,求有多少種剪法剪短其中的某些邊使得還連著的每一塊都有相同的點數,注意:不能不剪,可以全剪
樣例輸入:
61 2
2 32 4
4 55 6
樣例輸出:
用鄰接表儲存圖:
cin>>n;for (int i=1;i<=n-1;i++)
用深搜列舉出每一棵子樹的結點數,(這裡我竟然對無向圖的鄰接表琢磨了好久,s[x]表示以x為根的子樹的結點數)。
int dfs(intx)
return ++s[x];
}
需要注意的是,進入深搜只要寫:s[1]=dfs(1);即可。
然後就是最激動人心的部分:
先列舉每塊的大小k,有兩個顯然但是比較難想到的性質:
1.如果某個子樹的大小不是k的倍數,那麼這個子樹的根一定和其父親在乙個連通塊內。
證明:否則這個子樹就要被分成若干個大小為k的塊,但是其大小又不是k的倍數,必定不可能。
2.如果某個子樹的大小是k的倍數,那麼這個子樹的根一定不和其父親在乙個連通塊內。
證明:否則這個子樹中其它的點都要自己解決,那麼這個連通塊的點一定也是k的倍數,進一步地,一定恰好是k。但是這麼一來,根就不可能再往上多連了。
然後最終結論:如果恰好有n/k個子樹的大小是k的倍數,則k是乙個可行的方案。
於是預處理出所有子樹大小後列舉k,然後每個k暴力統計各個倍數出現了幾次即可。
for (k=2;k<=n;k++)if (n%k==0
)
DFS求聯通塊
題目 輸入乙個m行n列的字元矩陣,只要有兩個 相鄰就能組成乙個聯通塊,如下面的字元矩陣有2個聯通塊分析 將字元矩陣看作乙個圖,用dfs對圖中的字元遍歷,從每個 出發,遍歷 周圍的字元。每次訪問時給該位置打上塊標誌,表示已訪問,從而避免多次訪問同乙個位置。include include define ...
強聯通塊tarjan演算法
第一問 需要幾個學校存在軟體,才能通過傳遞,使得所有的學校都有軟體 用tarjan演算法求出強聯通分量後,將每個聯通分量縮成乙個點,那麼問題1的答案就是入度為0的點的個數 為什麼?入度為0的點,肯定不能通過其他學校傳送軟體給他,所以他必須存在乙份軟體 第二問 需要加幾條邊,才能使得圖強聯通 縮點後,...
Dmy 樹上聯通塊
include define rep i,a,b for int i a i b i using namespace std using ll long long template void chkmax t x,t y template void chkmin t x,t y constexpr ...