n
nn個點的一棵樹,k
kk個關鍵點,兩個人從根出發分別走一段路徑回到根。要求每個關鍵點至少被乙個人經過,求最短時間。
相當於求兩個覆蓋所有關鍵點的聯通子圖,使得最大那棵最小。
樹上只留下關鍵點和它們的祖先節點,這樣就變為了所有點都要經過,也就是所有葉子都要經過。
然後比較顯然的結論是一定會按照dfs
dfsdf
s從小到大的順序走,所以可以直接dpdp
dp。設f i,
j,kf_
fi,j,k
表示兩個人分別走到i,j
i,ji,
j,目前第二棵樹的大小為k
kk時第一棵樹的最小大小。
注意轉移x
−>
ix->i
x−>
i的時候權值得是dis
(lca
(x,i
),i)
dis(\ lca(x,i),i\ )
dis(lc
a(x,
i),i
),因為是聯通子圖上延伸下來一條路徑。
時間複雜度o(n
3)
o(n^3)
o(n3)
因為是比賽的時候寫的**改的,所以比較醜。
#include
#include
#include
using
namespace std;
const
int n=
420;
struct nodea[n<<1]
;int n,k,tot,num,ls[n]
,dep[n]
,f[n]
,lca[n]
[n],ans,dp[n]
[n][n]
,son[n]
;bool mark[n]
;void
addl
(int x,
int y)
bool
calc
(int x,
int fa)
return mark[x];}
void
dfs(
int x,
int fa)
if(flag||x==
1)son[
++num]
=x;for
(int i=ls[x]
;i;i=a[i]
.next)
return;}
intlca
(int x,
int y)
intdis
(int x,
int y)
intmain()
for(
int i=
1;i<=k;i++
)calc(1
,1);
dfs(1,
1);for
(int i=
1;i<=n;i++
)for
(int j=
1;j<=n;j++
) lca[i]
[j]=
lca(i,j)
;memset
(dp,
0x3f
,sizeof
(dp));
ans=dp[1]
[1][
0];dp[1]
[1][
0]=0
;son[
++num]=1
;for
(int i=
2;i<=num;i++
)for
(int x=
1;x)for
(int y=
1;yfor(
int i=
0;i<=num;i++
)for
(int j=
0;j<=num;j++
)printf
("%d\n"
,ans*2)
;}
P7276 送給好友的禮物 dp
n 個點的一棵樹,k 個關鍵點,兩個人從根出發分別走一段路徑回到根。要求每個關鍵點至少被乙個人經過,求最短時間。相當於求兩個覆蓋所有關鍵點的聯通子圖,使得最大那棵最小。樹上只留下關鍵點和它們的祖先節點,這樣就變為了所有點都要經過,也就是所有葉子都要經過。然後比較顯然的結論是一定會按照 dfs 從小到...