CodeForces 219D-H - Choosing Capital for Treeland-树DP

来源:互联网 发布:协同过滤算法python包 编辑:程序博客网 时间:2024/05/23 19:17

http://codeforces.com/problemset/problem/219/D

题意:

给出一树的节点n和有向边n-1条,

对每个点有个信息:该点到所有其他点,如果遇到一条反向边,计数器+1,


求出,最后这个计数器最小的点,如果有多个,增序输出

题目本身是无根树,为了方便我们直接看成一个以1为根的有根树即可:

显然是一个树DP,

我们把正向边权值val为0,反向边权值为1

第一次dfs,自底向上求出每个节点的到所有叶子节点所遇到的反向边数之和  dn[x]


然后对每个节点,要求题目所要求的信息,我们还缺【该节点到根节点的反向边数量,和 到兄弟节点的反向边数量


到根结点的好求,我们只需要再来个dfs2,这次自上向下,每到达一个节点,给up[x]加上从根到当前节点的反向边数量。

然后对于到兄弟节点的反向边的话需要利用父亲节点的信息,就等于 dn[x]-dn[v]-(!val)  【val是边权】 


#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <queue>#include <map>#include <set>#include <vector>#include <iostream>using namespace std;const double pi=acos(-1.0);double eps=0.000001; int min(int a,int b){return a<b?a:b;}struct node{int x,v,id;node(int a=0,int b=0,int c=0){x=a,v=b;id=c;}};vector<node> mp[200005];int up[200005];int dn[200005];int vis[200005];int ans[200005];int ok=0; void dfs2(int x ){ vis[x]=1;int i;for (i=0;i<mp[x].size();i++){int v=mp[x][i].x;int val=mp[x][i].v; val=!val;if (vis[v])continue;up[v]=val+dn[x]-dn[v]-(!val)+up[x];dfs2(v);   }}int dfs1(int x ){ int i;vis[x]=1;for (i=0;i<mp[x].size();i++){int v=mp[x][i].x;int val=mp[x][i].v;if (vis[v])continue;dn[x]+=val;dn[x]+=dfs1(v);} return dn[x]; } int main(){int n;cin>>n; int i,j;int x,y;for (i=1;i<n;i++){scanf("%d%d",&x,&y);mp[x].push_back(node(y,0,i));mp[y].push_back(node(x,1,i));}dfs1(1);memset(vis,0,sizeof(vis));dfs2(1);int minn=1e9,maxi=-1;for (i=1;i<=n;i++)  minn=min(minn,up[i]+dn[i]);  for (i=1;i<=n;i++) {if (minn==up[i]+dn[i])ans[++ok]=i;}   printf("%d\n",minn);for (i=1;i<=ok;i++)printf("%d ",ans[i]);printf("\n"); return 0;}


0 0
原创粉丝点击