NOIP2018 賽道修建(樹形dp 二分)

2022-03-17 01:25:53 字數 1462 閱讀 2460

弱雞萌新2023年難忘的騙分之旅

花了2個小時騙分2333

從n個點構成的的樹中取出m條邊不重複路徑,使得最小的路徑最長

由於沒有乙個確定的限制且問題具有單調性,首先肯定想到二分答案,設該數為x,那麼需要找出長度大於等於x的路徑條數

對於乙個子樹i,考慮它的貢獻,分為兩種:① i子樹中選一條或兩條鏈,使它們拼起來大於等於x ,② 父親節點通過連向i子樹的這條邊使用i子樹中的一條鏈,這個貢獻最多只能有一次(因為父親到i的邊只有一條)。那麼把哪一條鏈貢獻給父親呢?使用貪心策略

貪心:讓i子樹自己內部能配對的盡量配對,達到最多的配對數之後,將未配對的最大鏈貢獻給父親即可。這樣的正確性是顯然的,因為如果i子樹中有兩條鏈本來可以配對卻不讓它們配對,那麼路徑數少1,把其中一條貢獻給父親,通過2中敘述可知,這樣最多使路徑數加1,但是會多浪費一些父親子樹中的一些邊,肯定不如直接配對。

在使配對數最多的情況下,由於還要把未配對最大鏈貢獻給父親,所以這時候可以二分最大的鏈,檢驗如果沒有用這條鏈,是否還能達到最大匹配數,如果能則說明可以不用這條鏈,即可以貢獻給父親

上述思路總結起來的實現就是: 二分+排序+二分

排序用vector或者multiset即可

code:

#include#define n 50005

using namespace std;

const int inf = 2000000000;

int n,m,limit,sum;

vector e[n];

struct edge

edge[n<<1];int head[n],cnt=1;

void add_edge(int from,int to,int dis)

template void read(t &x)

bool ck(int rt,int pos,int l,int r,int goal)//不用pos是否能湊出goal個

int dfs(int rt,int fa)

if(e[rt].empty()) return 0;

sort(e[rt].begin(),e[rt].end());

int l=0,r=(int)e[rt].size()-1;

while(e[rt][r]>=limit) ++sum,--r;//單獨成鏈

int rest=r+1,tot=0;

while(l>1;

if(ck(rt,mid,0,rest-1,tot)) l=mid+1,ret=max(mid,ret);

else r=mid-1;

} return e[rt][ret];

}bool check(int x)//求所有大於等於x長度的賽道

int main()

printf("%d\n",ans);

return 0;

}

NOIP2018 賽道修建

noip2018 賽道修建 樹形結構不帶樹上演算法走典型。用 dfs 即可,考慮的方向不能脫離樹狀結構。即考慮一棵子樹中分出的路線一定是獨立的,而那些沒用的邊可以傳上去作為備選答案。再考慮乙個貪心,我們每次上傳最大的即可。includeusing namespace std namespace ae...

NOIP2018 賽道修建 考場

題意 在一棵樹上選出m條路徑,這些路徑不能共用任意一條邊 問這些路徑中最小的一條路最大是多少這道題的部分分十分有意思,搞了一搞 第一種情況是m 1,即只選出一條最長的路徑 顯然是計算樹的直徑 int fa n ans 0 int dfs1 int u ans max ans,sum1 sum2 re...

競賽題解 NOIP2018 賽道修建

額 考試的時候大概猜到正解,但是時間不夠了,不敢寫,就寫了騙分qwq 現在把坑填好了 copy from 洛谷 c 城將要舉辦一系列的賽車比賽。在比賽前,需要在城內修建 m 條賽道。c 城一共有 n 個路口,這些路口編號為 1,2,n 有 n 1 條適合於修建賽道的雙向通行的道路,每條道路連線著兩個...