FZOJ 2185 树的路径覆盖(YY+DFS)

Problem 2185 树的路径覆盖

Accept: 37    Submit: 118
Time Limit: 2000 mSec    Memory Limit : 32768 KB

Problem Description

給一棵树, 用最少的路径去覆盖所有的边, 求(1)允许边被重复覆盖, (2)不允许边被重复覆盖.

Input

第一行是组数T(T <= 20). 每组两行, 第一行是n(1 <= n <= 10^5), 第二行是n - 1个数(0-based), 第i个数x[i]表示有一条边(x[i], i + 1), (0 <= i <= n - 2).

Output

两个值,第一个值是允许边被重复覆盖情况下的答案,第二个值是不允许边被重复覆盖下的答案,用一个空格分隔.

Sample Input

2170 0 1 1 2 2

Sample Output

0 02 3






思路:先YY出规律,重复覆盖就是和分枝的一半有关,不重复覆盖就是和总非同一节点的分枝数有关。
//Accepted 2576 625ms GNU C++ 
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 1e5+100;

int head[N];
struct Edge
{
    int to;
    int next;
}es[N<<1];


int son[N];
int n;
int ans1,ans2;
void dfs(int rt,int pa)
{
    int cnt=0;
    bool first=1;
    for(int i=head[rt];~i;i=es[i].next)
    {
        int v=es[i].to;
        if(v==pa) continue;
        if(first)
            first=0;
        else
        {
            ans1++;
            cnt++;
        }
        dfs(v,rt);
    }
    ans2+=cnt/2+cnt%2; //剔除同一节点的分枝数
}

void ini()
{
    memset(head,-1,sizeof(head));
    memset(son,0,sizeof(son));
    ans1=ans2=0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        ini();
        for(int v=1;v<n;v++)
        {
            int u;
            scanf("%d",&u);
            es[v].to=v;
            es[v].next=head[u];
            head[u]=v;
            es[v+n].to=u;
            es[v+n].next=head[v];
            head[v]=v+n;
            son[u]++;
            son[v]++;
        }
        for(int i=n-1;i>=0;i--)
            if(son[i]==1)
            {
                dfs(i,-1);
                ans1++;
                ans2++;
                break;
            }
        if(ans1)
            printf("%d %d\n",(ans1-1)/2+(ans1-1)%2+1,ans2);
        else
            printf("0 0\n");
    }
    return 0;
}


你可能感兴趣的:(FZOJ 2185 树的路径覆盖(YY+DFS))