HDU 5758 Explorer Bo

来源:互联网 发布:编程入门学什么语言 编辑:程序博客网 时间:2024/05/18 00:05

Description

Explorer Bo likes exploring mazes around the world.Now he wants to explore a new maze.
The maze has N rooms connected with N−1 roads of length 1 so that the maze looks like a tree.
Explorer Bo can transfer to a room immediately or walk along a road which is not the one he walked just now.
Because the transfer costs too much, Mr Bo will minimum the transfer using times firstly.
Mr Bo wants to walk along all the roads at least once,but he is lazy and he wants to minimum the total length he walked.
Please help him!
Initial point can be arbitrarily selected

Solution
orz ShinFeb
这个问题比赛的时候想完了70%,剩下30%死也想不到了,orz ShinFeb大爷给出了一个超神的解决方案。
比赛的时候没做出来很愧疚啊。。感觉对不起大家

这题显然dp
那个瞬移次数是可以确定的,=2(画个图就可以出来,因为一般情况下起点肯定是一个叶子节点,终点也是一个叶子节点)
对于一棵以v为根的子树,我们记其叶子节点个数为sz[v]
考虑其一个子节点to
如果sz[to]0 mod 2,那么vto的边会被走两遍吧(因为如果叶子节点互相走这条边不会被走到不满足题设)
反之vto的边只会被走一遍
那么可以直接dp解决。
然而如果叶子节点个数是奇数,那么有一段路径可以省掉,那咋办?
ShinFeb给了一个很好的方案
假设根节点是一个叶子节点。
我们先dp
然后考虑从根节点开始删除一段区间。
对于经过的点,只要把1反转成2,2反转成1即可。
然后求一下可以缩减的最大值即可

Code

#include<iostream>#include<string.h>#include<stdio.h>#include<algorithm>#include<vector>using namespace std;typedef long long ll;typedef vector<int> vec;#define ph push#define pb push_backconst int M=1e5+5;vec G[M];inline void Max(int &a,int b){    if(a<b)a=b;}inline void Min(int &a,int b){    if(a>b)a=b;}inline void rd(int &a){    a=0;char c;    while(c=getchar(),!isdigit(c));    do a=a*10+(c^48);        while(c=getchar(),isdigit(c));}ll dp[M];int sz[M];bool mark[M];void dfs(int v,int f){    bool flag=0;    for(int i=0;i<G[v].size();++i){        int to=G[v][i];        if(to==f)continue;        dfs(to,v);        if(sz[to]&1)++dp[v];        else dp[v]+=2;        dp[v]+=dp[to];        sz[v]+=sz[to];        flag=1;    }    if(!flag)mark[v]=1,sz[v]=1;}int Mx=0;inline void rdfs(int v,int f,int dlt){    Max(Mx,dlt);    for(int i=0;i<G[v].size();++i){        int to=G[v][i];        if(to^f)rdfs(to,v,dlt+(sz[to]&1?-1:1));    }}inline void gao(){    int n;cin>>n;    for(int i=1;i<=n;++i)G[i].clear();    memset(dp,0,sizeof(dp));    memset(sz,0,sizeof(sz));    Mx=0;    for(int i=1,a,b;i<n;++i){        rd(a),rd(b);        G[a].pb(b),G[b].pb(a);    }    int s;    for(int i=1;i<=n;++i)        if(G[i].size()==1)s=i;    dfs(s,s);    rdfs(s,s,0);    ++sz[s];    if(sz[s]&1)cout<<dp[s]-Mx<<endl;    else cout<<dp[s]<<endl;}int main(){    int _;    for(cin>>_;_--;)gao();    return 0;}
2 0
原创粉丝点击