【定義】
我們將一棵樹t = ( v,e )的直徑定義為maxδ ( u,v ) ( u,v ∈ v ),也就是說,樹中所有最短路徑距離的最大值即為樹的直徑。
題意:若是乙個數x的所有約數(不包括他自己)之和sum比他自己小,
那麼x可以轉化成sum,sum也可以成 x。例如 4可以變為 3,1可以變為7
限制所有數字在不超過n的正整數範圍內轉換,求數字變換滿足無重複數字情況下的最多變換步數 。當n=7,最長為 4->3>1>7
解法1,樹形dp
我們令f1[rt]表示以rt為根的樹,根節點到葉節點的最長距離 , f2[rt]表示以rt為根的樹 , 根節點到葉節點的次最長距離 ,並且這個葉節點和最長距離的那個葉節點不在同乙個子樹中。
那麼易知(好吧是因為我不會證明qaq)樹的直徑d=max(f1[i]+f2[i])
很明顯葉子節點就是邊界,遞推過程就是葉->根。
設j為i的孩子節點,
如果f1[j]+w[i][j]>f1[i] 那麼f2[i]=f1[i] ,f1[i]=f1[j]+w[i][j]
否則,如果f1[j]+w[i][j]>f2[i] 那麼f2[i]=f1[j]+w[i][j]
(注意://這裡由於是不同的子樹j不斷更新i,所以可以保證f1[i] f2[i] 不會走同乙個子樹)
簡而言之就是,
孩子節點+距離如果能更新最長鏈,次長鏈就更新為原先最長鏈的值,最長鏈就被孩子節點更新。 如果不能,就看看能不能更新次長鏈。
題目**:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
#define ll long long
#define ull unsigned long long
const
int inf=
0x3f3f3f
;const
double eps=
1e-5
;const
int maxn=
5e4+10;
/*題意:若是乙個數x的所有約數(不包括他自己)之和sum比他自己小,
那麼x可以轉化成sum,sum也可以成 x。例如 4可以變為 3,1可以變為7
限制所有數字變換在不跨越 n的正整數範圍內舉行轉化,求不停舉行數字變換且無重複數字的最多變換步數*/
int sum[maxn]
;//預處理每個數的約數之和
int f1[maxn]
,f2[maxn]
;//f1:以i為根的樹中,i到葉子節點的最長距離,f2 :....次長距離
//直徑就是 max(f1[i]+f2[i]) 就是樹中所有的兩點最短距離中的最大值
//int n;
void
getsum()
//預處理每個數的約數之和}}
intmain()
else
if(f1[i]+1
>f2[sum[i]
]) f2[sum[i]
]=f1[i]+1
;}int ans=-1
;for
(int i=
1;i<=n;i++
) ans=
max(ans,f1[i]
+f2[i]);
printf
("%d\n"
,ans)
;system
("pause");
return0;
}
解法2兩次dfs
從圖中任意一點p出發,到最遠的點w,再從w出發到離w最遠的點q,wq的距離就是樹的直徑,直接兩次dfs就可以求出圖的直徑,樹也是圖的一種,所以一樣的
證明如下:
①若p已經在直徑上,根據樹的直徑的定義可知q也在直徑上且為直徑的乙個端點
②若p不在直徑上,我們用反證法,假設此時wq不是直徑,ab是直徑
—>若ab與pq有交點c,由於p到q最遠,那麼pc+cq>pc+ca,所以cq>ca,易得cq+cb>ca+cb,即cq+cb>ab,與ab是直徑矛盾,不成立,如下圖(其中ab,pq不一定是
直線,畫成直線是為了方便):
—>若ab與pq沒有交點,m為ab上任意一點,n為pq上任意一點。首先還是np+nq>nq+mn+mb,同時減掉nq,得np>mn+mb,易知np+mn>mb,所np+mn+ma>mb+ma,
即np+mn+ma>ab,與ab是直徑矛盾,所以這種情況也不成立,如下圖:
題目**
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
#define ll long long
#define ull unsigned long long
const
int inf=
0x3f3f3f
;const
double eps=
1e-5
;const
int maxn=
5e5+10;
/*題意:若是乙個數x的所有約數(不包括他自己)之和sum比他自己小,
那麼x可以轉化成sum,sum也可以成 x。例如 4可以變為 3,1可以變為7
限制所有數字變換在不跨越 n的正整數範圍內舉行轉化,求不停舉行數字變換且無重複數字的最多變換步數*/
struct
edge[maxn]
;//前向星存圖
int head[maxn]
;int cnt=1;
int sum[maxn]
;//預處理每個數的約數之和
int n;
int mmax,q;
//q為第一次dfs到達的最遠距離
bool vis[maxn]
;void
getsum()
}}void
add(
int v,
int to)
void
dfs(
int st,
int tmax)
//目前到達點和當前最遠距離
vis[st]=1
;for
(int j=head[st]
;j;j=edge[j]
.next)
//前向星遍歷這裡,自己是忘記head[i]是以i出發的最後一條邊的下標 ,還是不夠熟練}}
intmain()
dfs(1,
0);memset
(vis,0,
sizeof
(vis));
//第一次dfs 求出從1出發到達最遠點q
mmax=0;
dfs(q,0)
;printf
("%d\n"
,mmax)
;system
("pause");
return0;
}
一本通 1 1 例 2 種樹
題目傳送門 這題的題目問的是要滿足所有居民的建議,至少要種多少棵樹。對於這種題目,我們首先想到的應該是貪心策略。貪心策略 首先按右端點從小到大排序,因為要求樹最少,所以要盡量放在右端點。然後定義乙個bool陣列判斷該點是否種過樹即可。從右端點開始種,可以讓更多的樹照顧到更右側的端點,這樣就能使種的數...
10001 一本通 1 1 例 2 種樹
題目題目題目 題目描述 某條街被劃為 n條路段,這 n 條路段依次編號為 1 n。每個路段最多可以種一棵樹。現在居民們給出了 hhh 組建議,每組建議包含三個整數 b,e,t,表示居民希望在路段 b 到 e 之間至少要種 t 棵樹。這些建議所給路段的區間可以交叉。請問 如果要滿足所有居民的建議,至少...
一本通題解 題解一維陣列 1107 校門外的樹
時間限制 1000 ms 記憶體限制 65536 kb 題目描述 某校大門外長度為l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸0的位置,另一端在l的位置 數軸上的每個整數點,即0,1,2,l,都種有一棵樹。由於馬路上有一些區域要用來建地鐵。這些...