CSU 2036 Getting Back Home(分类讨论)

2036: Getting Back Home

Submit Page    Summary    Time Limit: 3 Sec     Memory Limit: 512 Mb     Submitted: 30     Solved: 9    

Description

Arman has recently moved to a remote village in the country-side. The map of the village is in the form of a tree, i.e. there are exactly n − 1 roads connecting n intersections of the village such that for every pair of intersections there is a sequence of roads connecting them. Every morning Arman goes to his office and late at night he gets back home. It is very dark at night and the village roads do not have any lights so Arman is starting to have problems finding his way back home. There are no signs at intersections and he cannot distinguish them from each other. Even his phone is not signalling on the way, and using GPS is not possible. To solve the problem, he has decided to buy a flashlight. Flashlights have different integer beam distances, and a flashlight with a higher beam range costs more. A flashlight with range d reveals the intersections within a distance at most d around the current intersection. All roads of the village have an equal length of 1. When Arman leaves office towards home, in every intersection of the path he traverses, he makes a decision as explained below. 1. If he sees home, he just moves towards it. 2. Assume he is at intersection u. Let A be the set of all roads incident to u. Let B be the empty set at the initial time, and {e} otherwise where e is the road he just arrived at u through it. Moreover, let C be the set of useless roads incident to u. A road e′ incident to u is called useless if all simple paths starting at u and passing through e′ have length less than d. If A − (B ∪ C) is not empty, one road of this set is chosen randomly. Otherwise, the road e is chosen again. Arman doesn’t care about walking a little bit longer as long as he knows regardless of his random choices, he will eventually reach home after passing through at most 109 roads. He wants to purchase the cheapest flashlight for that purpose. Please help him find the appropriate flashlight by which he would be able to reach home.

Input

There are multiple test cases in the input. For each input the first line contains an integer n, the number of intersections in the village (2 ⩽ n ⩽ 30, 000). Next n − 1 lines each contains two integers a, b meaning that there is a road between intersections a and b (1 ⩽ a, b ⩽ n). Arman’s home is at intersection 1 and his office is at intersection n. The input terminates with a line containing “0” which should not be processed.

Output

For each test case, output a single line containing the minimum range d of a flashlight that guarantees Arman can al- ways reach home after passing through at most 109 roads regardless of his random choices. If Arman does not need any flashlight, print “0”.

Sample Input

7
1 2
2 3
3 7
4 5
5 7
6 7
0

Sample Output

2

Hint

Source

ATRC2017




      大致题意:给你一棵树,让你从n点出发,你的家在1点。你有一个手电筒,可以照亮范围为k的区域。你沿着树的边走,走到岔路口时,利用手电筒的范围看每一条路是否能看到家或者看到是死路,如果是家,那么直接往家里走;如果是死路,那么不走这个路口;如果不知道,那就随机走一条可以走的路口走。如果走到尽头,那么原路返回。现在问如果最坏情况下你也一定能够走到家,手电筒的照亮范围k最小是多少。
      既然要求是最后能够走到家的最小k,那么我们先考虑哪种情况会使得不能到家,也即一直在树里面循环。利用下图来考虑:

           
    Cur表示当前点,Before表示之前来的路,c表示之前来的路的长度,a和b表示除了到家的路之外的最长和次长的路,fir和sec分别对应表示二者的长度,th表示到家的长度。
       首先,如果最坏情况下能够到达家,那么一定不会走到b这条路。因为如果走到,意味k<sec,那么当我返回的时候,还有可能走到a这条路,也就可能会在a、b两条路之间循环走,所以k>sec。
       其次,我们可以考虑k<fir,也即可以走到a这条路再出来。第一个条件,要出来,那么一定也不能在a的子树里面循环,同样的要在a这条路对应的子树节点里,找一个最大的sec,为了区分记为sub,使得k>sub。第二个条件,要出来,那么返回的时候一定也不能又走到Before那条路,所以说k>c。

       综上,对于一个点满足k>c、k>sub、k>sec即可。但是,在具体做的时候还要分类考虑一些问题,比如说k肯定比th小以及有些时候根据题意要加一。具体见代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#define N 30010
using namespace std;

int d[N],deep[N],n;
vector<int> g[N];
bool v[N];

void dfs(int x,int fa,int dep)
{
    d[x]=dep;
    deep[x]=0;
    v[x]=(x==1);
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if (y==fa) continue;
        dfs(y,x,dep+1); v[x]|=v[y];
        deep[x]=max(deep[x],deep[y]+1);
    }
}

void getsub(int x,int fa,int &sub)
{
    int fir=0,sec=0;
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if (y==fa) continue;
        if (deep[y]+1>fir)
        {
            sec=fir,fir=deep[y]+1;
            sub=max(sec,sub);
        } else
        {
            sec=max(sec,deep[y]+1);
            sub=max(sec,sub);
        }
        getsub(y,x,sub);
    }
}

void solve(int x,int fa,int &k,int c)
{
    if (x==1) return;
    if (d[1]-d[x]<k) return;
    int fir=0,sec=0,nxt,z;
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if (fa==y) continue;
        if (v[y]) {nxt=y;continue;}
        if (deep[y]+1>fir) sec=fir,fir=deep[y]+1,z=y;
                         else sec=max(sec,deep[y]+1);
    }
    int h=d[1]-d[x];
    if (fir)
    {
        int sub=0;
        int tmp=max(c,sec);
        if (tmp<fir)
        {
            getsub(z,x,sub);
            tmp=max(tmp,sub);
            if (tmp) k=max(k,tmp+1);
        } else k=max(k,fir+1);
        k=min(k,h);
    }
    solve(nxt,x,k,max(fir,c)+1);
}

int main()
{
    while(~scanf("%d",&n))
    {
        if (n==0) break;
        for(int i=0;i<=n;i++) g[i].clear();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(n,0,0);
        int ans=0;
        solve(n,0,ans,0);
        printf("%d\n",ans);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值