1389. Roadworks

http://acm.timus.ru/problem.aspx?space=1&num=1389

一维树形DP 不难 关键在于输出类似路径的选择

求完最优答案 再顺着答案走一遍就可以了

关键:

从一个节点出发的各条 road 中 如果某一条 road 被 block 则相连的下一个节点开始的路都不能进行 block

如果某一条路没有被 block 则相连下一个节点开始的路可以进行选择性的是否 block

但要注意从一个点出发的 road 最多只能有一个block

代码及其注释:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <queue>

#include <vector>

#include <algorithm>



#define LL long long

//#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;

const int N=100005;

int head[N],I;

struct node

{

    int j,next;

    int k;

}side[N*2];

struct node1

{

    int l,r;

    bool blocked;

}road[N];//输入的路 blocked 代表是否 被堵

int block[N];//以此节点为根的树 从根节点出发的路有一条被堵的最优结果

int select[N];//对应被堵的路是哪一条

int noblock[N];//以此节点为根的树 从根节点出发的路没有被堵的最优结果

void build(int i,int j,int k)

{

    side[I].j=j;

    side[I].k=k;

    side[I].next=head[i];

    head[i]=I++;

}

int dpblock(int x,int pre);

int dpnoblock(int x,int pre)

{

    if(noblock[x]!=-1)

    return noblock[x];

    noblock[x]=0;

    for(int t=head[x];t!=-1;t=side[t].next)

    {

        int l=side[t].j;

        if(l==pre)

        continue;

        noblock[x]+=max(dpnoblock(l,x),dpblock(l,x));//以往下节点开始的路 既可以堵也可以不堵

    }

    return noblock[x];



}

int dpblock(int x,int pre)

{

    if(block[x]!=-1)

    return block[x];

    block[x]=0;

    int temp=-1,w=-1;

    for(int t=head[x];t!=-1;t=side[t].next)

    {

        int l=side[t].j;

        if(l==pre)

        continue;

        block[x]+=max(dpnoblock(l,x),dpblock(l,x));

        if(temp==-1||(noblock[l]-max(noblock[l],block[l]))>(noblock[temp]-max(noblock[temp],block[temp])))

        {temp=l;w=side[t].k;}//对哪条路堵 进行取舍

    }

    if(temp==-1)//注意叶子节点情况

    return block[x];

    block[x]+=(noblock[temp]-max(noblock[temp],block[temp]))+1;

    select[x]=w;

    return block[x];

}

void dfsnoblock(int x,int pre);

void dfsblock(int x,int pre)//根据最优路径 标记答案

{

    if(select[x]!=-1)

    road[select[x]].blocked=true;

    for(int t=head[x];t!=-1;t=side[t].next)

    {

        int l=side[t].j;

        if(l==pre)

        continue;

        if(side[t].k==select[x])

        {dfsnoblock(l,x);continue;}

        if(block[l]>noblock[l])

        dfsblock(l,x);

        else

        dfsnoblock(l,x);

    }

}

void dfsnoblock(int x,int pre)//根据最优路径 标记答案

{

    for(int t=head[x];t!=-1;t=side[t].next)

    {

        int l=side[t].j;

        if(l==pre)

        continue;

        if(block[l]>noblock[l])

        dfsblock(l,x);

        else

        dfsnoblock(l,x);

    }

}

int main()

{

    //freopen("data.txt","r",stdin);

    int n,m;

    while(scanf("%d %d",&n,&m)!=EOF)

    {

        memset(head,-1,sizeof(head));

        I=0;

        for(int i=1;i<=m;++i)

        {

            scanf("%d %d",&road[i].l,&road[i].r);

            build(road[i].l,road[i].r,i);

            build(road[i].r,road[i].l,i);

        }

        memset(block,-1,sizeof(block));

        memset(noblock,-1,sizeof(noblock));

        memset(select,-1,sizeof(select));

        printf("%d\n",max(dpblock(1,-1),dpnoblock(1,-1)));

        for(int i=1;i<=m;++i)

        road[i].blocked=false;

        if(block[1]>noblock[1])

        dfsblock(1,-1);

        else

        dfsnoblock(1,-1);

        for(int i=1;i<=m;++i)

        {

            if(road[i].blocked==true)

            printf("%d %d\n",road[i].l,road[i].r);

        }

    }

    return 0;

}



 

 

你可能感兴趣的:(OA)