#NOIP模拟赛#捕鼠器mousetrap(树)

本文提供了一个关于鼠标陷阱问题的详细解答,通过C++代码实现,包括深度优先搜索(DFS)来确定路径长度,并使用额外的数据结构来计算移动成本。文章包含完整的算法流程,适用于竞赛编程爱好者和技术人员参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题解其实是相当详细的,但是是英文的,于是我就自己翻译了一份(拒转载,心血啊),有可能有错,但是并不影响大部分的理解,可以参考。


Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int Max = 1000000;

int N, Root, Mouse;
int fa[Max + 5], Path[Max + 5], Mova[Max + 5];

vector<int>Child[Max + 5];
vector<pair<int, int> >L;

bool getint(int & num){
    char c; int flg = 1;    num = 0;
    while((c = getchar()) < '0' || c > '9'){
        if(c == '-')    flg = -1;
        if(c == -1) return 0;
    }
    while(c >= '0' && c <= '9'){
        num = num * 10 + c - 48;
        if((c = getchar()) == -1)   return 0;
    }
    num *= flg;
    return 1;
}

int Dfs(int u, int ff){
    fa[u] = ff;
    int p;
    for(p = 0; p < Child[u].size() && Child[u][p] != ff; ++ p);
    if(p < Child[u].size())	Child[u].erase(Child[u].begin() + p);
    int dis = -1;
    if(u == Mouse)  dis = 0;
    for(int i = 0; i < Child[u].size(); ++ i)
        dis = max(dis, Dfs(Child[u][i], u));
    Path[u] = dis;
    if(dis == -1)   return dis;
    else return dis + 1;
}

void Get_Cost(int u, int d){
    if(Child[u].size() == 0){
        Mova[u] = d;
        return ;
    }
    if(Path[u] == -1){
        int tmp = d + Child[u].size();
        for(int i = 0; i < Child[u].size(); ++ i)
            Get_Cost(Child[u][i], tmp);
        if(Child[u].size() == 1){
            Mova[u] = d + 1;
            return ;
        }
        int fir = -1, sec = -1;
        for(int i = 0; i < Child[u].size(); ++ i){
            int v = Child[u][i];
            if(Mova[v] > fir){
                sec = fir, fir = Mova[v];
                continue;
            }
            if(Mova[v] > sec)   sec = Mova[v];
        }
        Mova[u] = sec;
        return ;
    }
    int tmp = d + Child[u].size() - 1;
    if(u == Root)  tmp = 0;
    if(u == Mouse)  ++ tmp;
    for(int i = 0; i < Child[u].size(); ++ i)
        Get_Cost(Child[u][i], tmp);
    if(u == Root)   return ;
    for(int i = 0; i < Child[u].size(); ++ i)   if(Path[Child[u][i]] == -1)
        L.push_back(make_pair(Path[u], Mova[Child[u][i]]));
}

int main(){
    freopen("mousetrap.in", "r", stdin);
    freopen("mousetrap.out", "w", stdout);
    getint(N), getint(Root), getint(Mouse);
    int u, v;
    for(int i = 1; i < N; ++ i){
        getint(u), getint(v);
        Child[u].push_back(v);
        Child[v].push_back(u);
    }
    int P = Dfs(Root, -1);
    Get_Cost(Root, 0);
    sort(L.begin(), L.end());
    int l = 0, r = N;
    while(l < r){
        int mid = (l + r) >> 1;
        int x = 0, y = 0, pt = 0;
        for(int i = 0; i < P; ++ i){
            if(pt >= L.size()){
                r = mid;
                break;
            }
            ++ x;
            int delta = 0;
            while(pt < L.size() && L[pt].first <= i){
                if(L[pt].second + y > mid)
                    ++ delta, -- x;
                ++ pt;
            }
            y += delta;
            if(x < 0 || y > mid){   l = mid + 1;    break;}
        }
    }
    printf("%d\n", l);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值