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