弱雞萌新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 條適合於修建賽道的雙向通行的道路,每條道路連線著兩個...