-
F - Choosing Capital for Treeland
- CodeForces - 219D
- 题意:给出具有N个节点的树,现在给出N-1条有向边,问我们最少改变多少条边的方向,使得我们能够从一个点。
- 到达其余所有的点。并且输出各个点的编号。
- 思路:第一遍dfs,dp里面存的是它到所有子树节点的需要翻转的次数,第二次更新ans存的是它到全体的节点的翻转次数
- ans[v]+=ans[u]-dp[v]-edge[i].flag+!edge[i].flag;
-
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 200050 int dp[maxn],s,t; int head[maxn],n; int tot,ans[maxn]; struct node { int v,flag,to; } edge[maxn*2]; void add(int u,int v) { edge[++tot].v=v; edge[tot].to=head[u]; edge[tot].flag=0; head[u]=tot; edge[++tot].v=u; edge[tot].to=head[v]; edge[tot].flag=1; head[v]=tot; } void dfs1(int u,int pre) { for(int i=head[u]; i!=-1; i=edge[i].to) { int v=edge[i].v; if(v==pre)continue; dfs1(v,u); dp[u]+=dp[v]+edge[i].flag; } } void dfs2(int u,int pre) { ans[u]+=dp[u]; for(int i=head[u]; i!=-1; i=edge[i].to) { int v=edge[i].v; if(v==pre)continue; ans[v]+=ans[u]-dp[v]-edge[i].flag+!edge[i].flag; dfs2(v,u); } } int main() { memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1; i<n; i++) { scanf("%d%d",&s,&t); add(s,t); } dfs1(1,-1); dfs2(1,-1); vector<int>qq; int sum=inf; for(int i=1; i<=n; i++) if(ans[i]<sum) sum=ans[i]; for(int i=1; i<=n; i++) if(ans[i]==sum)qq.push_back(i); sort(qq.begin(),qq.end()); int len=qq.size(); printf("%d\n",sum); for(int i=0; i<len; i++) if(i==len-1) printf("%d\n",qq[i]); else printf("%d ",qq[i]); return 0; }
F - Choosing Capital for Treeland -树形DP
最新推荐文章于 2022-04-06 18:02:44 发布