1389. Roadworks

原文链接: http://www.cnblogs.com/liulangye/archive/2012/09/22/2697854.html

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;
}

转载于:https://www.cnblogs.com/liulangye/archive/2012/09/22/2697854.html

猜你喜欢

转载自blog.csdn.net/weixin_30481087/article/details/94791700
今日推荐