\(n\)個點的一棵樹,\(k\)個關鍵點,兩個人從根出發分別走一段路徑回到根。要求每個關鍵點至少被乙個人經過,求最短時間。
相當於求兩個覆蓋所有關鍵點的聯通子圖,使得最大那棵最小。
樹上只留下關鍵點和它們的祖先節點,這樣就變為了所有點都要經過,也就是所有葉子都要經過。
然後比較顯然的結論是一定會按照\(dfs\)從小到大的順序走,所以可以直接\(dp\)。設\(f_\)表示兩個人分別走到\(i,j\),目前第二棵樹的大小為\(k\)時第一棵樹的最小大小。
注意轉移\(x->i\)的時候權值得是\(dis(\ lca(x,i),i\ )\),因為是聯通子圖上延伸下來一條路徑。
時間複雜度\(o(n^3)\)
因為是比賽的時候寫的**改的,所以比較醜。
#include#include#includeusing 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;
}int lca(int x,int y)
int dis(int x,int y)
int main()
}for(int i=0;i<=num;i++)
for(int j=0;j<=num;j++)
printf("%d\n",ans*2);
}
P7276 送給好友的禮物 dp
n nn個點的一棵樹,k kk個關鍵點,兩個人從根出發分別走一段路徑回到根。要求每個關鍵點至少被乙個人經過,求最短時間。相當於求兩個覆蓋所有關鍵點的聯通子圖,使得最大那棵最小。樹上只留下關鍵點和它們的祖先節點,這樣就變為了所有點都要經過,也就是所有葉子都要經過。然後比較顯然的結論是一定會按照dfs ...