P7276 送給好友的禮物 dp

2021-10-16 12:08:13 字數 2024 閱讀 8596

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 從小到...