树形dp

题意:给出了一棵树, 这个树上的边有两种类型,一种是保护的, 另一种是不保护的。 现在想让每个点到根节点中的路线中,受保护的边至少有一半, 现在至少要改变多少条变才能达到目的, 并输出修改边的方案。

思路:这道题是如果要改变边的话那么就尽量在靠近根节点的地方修改边。

我们用一个need保存这个子树中的点要满足要求需要改变边的数目。

 那么need[u] = max( (step+1)/2-have, need[v])  v是u的子节点。

 

然后就是建路的过程, 这个时候我犯了一个错误。 开始的时候我一直递归, 进行到修改边的数目大于等于需要的就停止。其实在进行带u,如果在u的v之间是否修路,看的不是need[u],而是v, 因为不满足u,但是可能满足v。如果满足了u,那么一定能够满足v。

AC代码:

 

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 200005, INF = 1<<25;
struct EDGE
{
    int v, next;
    int w;
} edge[N*2];

int num, head[N], need[N], ans[N], step;
int n;

void add(int u, int v, int w)
{
    edge[num].v = v;
    edge[num].w = w;
    edge[num].next = head[u];
    head[u] = num++;
}

void init()
{
    num = 0;
    memset(head, -1, sizeof(head));
    char str[30];
    int u, v;
    for(int i=1; i<n; i++)
    {
        scanf("%d%d%s", &u, &v, str);
        if(str[0] == 'a')
        {
            scanf("%s", str);
            add(u,v,0);
            add(v,u,0);
        }
        else
        {
            add(u,v,1);
            add(v,u,1);
        }
    }
}

void dfs(int u, int pre, int step, int path)
{
    need[u] = (step+1)/2 - path;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        if(edge[i].v == pre) continue;
        dfs(edge[i].v, u, step+1, path+edge[i].w);
        need[u] = max(need[u],need[edge[i].v]);
    }
    if(need[u] < 0) need[u] = 0;
}

void dfs1(int u, int pre, int now)
{
    int v;
    if(need[u] <= now) return;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        v = edge[i].v;
        if(v == pre) continue;
        if(now < need[v])
        {
            if(edge[i].w == 0)
            {
                ans[step++] = i/2+1;
                dfs1(edge[i].v,u,now+1);
            }
            else dfs1(edge[i].v,u,now);
        }
    }
}

void solve()
{
    dfs(1, -1, 0, 0);
    step = 0;
    dfs1(1,-1,0);
    printf("%d\n",step);
    sort(ans, ans+step);
    for(int i=0; i<step-1; i++)
        printf("%d ",ans[i]);
    if(step)
        printf("%d\n", ans[step-1]);
}

int main()
{
    while(scanf("%d", &n) != EOF)
    {
        init();
        solve();
    }
    return 0;
}

 

 

posted @ 2012-10-01 09:54  Gu Feiyang  阅读(272)  评论(0)    收藏  举报