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