cf219d 基础换根法

/*树形dp换根法*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
struct Edge{int to,nxt,flag;}edge[maxn<<1];
int root,n,s,t,head[maxn],tot,dp[maxn];
void init(){
    memset(head,-1,sizeof head);
    tot=0;
}
void addedge(int u,int v,int flag){
    edge[tot].to=v;edge[tot].nxt=head[u];edge[tot].flag=flag;
    head[u]=tot++;
}
void dfs1(int u,int pre){
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==pre)continue;
        if(edge[i].flag==0)dp[u]++;
        dfs1(v,u);
        dp[u]+=dp[v];
    }
}
void dfs2(int u,int pre){
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        dp[v]=dp[u]+(edge[i].flag==1?1:-1);
        if(v==pre)continue;
        dfs2(v,u);
    }
}
int main(){
    init();
    cin>>n;
    for(int i=1;i<n;i++){
        cin>>s>>t;
        addedge(s,t,1);
        addedge(t,s,0);
    }
    root=1;
    dfs1(1,0);//第一次dfs求出dp[1]
    dfs2(1,0);//第二次dfs求出剩下的结点
    int ans=99999999;
    for(int i=1;i<=n;i++)ans=min(ans,dp[i]);
    cout<<ans<<endl;
    for(int i=1;i<=n;i++)
        if(dp[i]==ans)cout<<i<<" ";
}

原文地址:https://www.cnblogs.com/zsben991126/p/10336970.html

时间: 2024-08-01 21:14:39

cf219d 基础换根法的相关文章

poj3585树最大流——换根法

题目:http://poj.org/problem?id=3585 二次扫描与换根法,一次dfs求出以某个节点为根的相关值,再dfs遍历一遍树,根据之前的值换根取最大值为答案. 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,head[200005],ct,d[200005],f[200005],deg[200005],ans,t; bool v

题解 poj3585 Accumulation Degree (树形dp)(二次扫描和换根法)

写一篇题解,以纪念调了一个小时的经历(就是因为边的数组没有乘2 phhhh QAQ) 题目 题目大意:找一个点使得从这个点出发作为源点,流出的流量最大,输出这个最大的流量. 以这道题来介绍二次扫描和换根法 作为一道不定根的树形DP,如果直接对每个点进行DP,可能时间会炸掉 但是,优秀的二次换根和扫描法可以再O(n^2)内解决问题. 二次扫描的含义:(来自lyd 算法竞赛进阶指南) 第一次扫描:任选一个节点为根节点(我会选1)在树上进行树形DP,在回溯时,从儿子节点向父节点(从底向上)进行状态转移

【51Nod1405】树上距离和 二次扫描与换根法

题目大意:给定一棵 N 个点的边权均为 1 的树,依次输出每个点到其他各个点的距离和. 题解:首先任意选定一个节点为根节点,比如 1,第一遍 dfs 遍历树求出子树大小.树上前缀和.第二遍 dfs 遍历这棵树,求出各个点的距离和. 对于遍历到的任意一个节点 i,对于与之相邻的节点 j 来说,答案贡献由 i 到 j 转移首先减小了 \(size[j]*1\),同时增加了 \((n-size[j])*1\),因此可以直接得到\(dp[j]=dp[i]+n-size[j]*2\). 代码如下 #inc

树形dp经典换根法——cf1187E

假设以u为根时结果是tot,现在转换到了以u的儿子v为根,那么结果变成了tot-size[v]+(sizetot-size[v]) 根据这个转移方程,先求出以1为根的tot,然后dfs一次转移即可 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define ll long long #define N 200005

换根DP

换根dp的通法:1.第一次扫描时,任选一个点为根,在"有根树"上执行一次树形DP,也就在回溯时发生的,自底向上的状态转移. 2.第二次扫描时,从刚才选出的根出发,对整棵树执行一次dfs,在每次递归前进行自上向下的推导,计算出换根后的解. 1.POJ3585 Accumulation Degree dp[i]以i为根的子树中,把i作为源点的最大流量 转移\(dp[x]=\sum_{y\epsilon son(x)}^{}\left\{\begin{matrix} min(dp[y],le

算法题:复制复杂链表之空间换时间法

说明:本文仅供学习交流,转载请标明出处,欢迎转载!  题目:复制一个复杂链表,所谓复杂链表指的是每个节点含有两个指针,一个指向单链表的下一个结点,一个指向单链表中的任意某个结点,或者该指针为空. 为了方便起见,我们将待复制的链表称为原型链表,将复制后的新链表称为复制链表,将指向下一个结点的指针定义为next指针,指向其他位置的指针定义为any指针.<剑指offer>上给出了三种解决方法:(1)常规法:(2)空间换时间法:(3)紧随复制法.书上并给出了第三种方法的实现代码.这里我根据书上的提示,

[转]二重积分换元法的一种简单证明

10.3二重积分的换元积分法 在一元函数定积分的计算中,我们常常进行换元,以达删繁就简的目的,当然,二重积分也有换元积分的问题. 首先让我们回顾一下前面曾讨论的一个事实. 设换元函数 ,视其为一个由定义域到的映射.点的象点为,点x的象点为,记 , 则由到点的线段长为,到的线段长为,称为映射在点到点的平均伸缩率.若在点处可导,则 = 即称是映射在点处的伸缩率. 对于由平面区域到的映射我们有如下结论: 引理 若变换在开区域存在连续偏导数,且雅可比行列式,.变换将平面上开区域变为平面上开区域.,其象点

特征根法求通项+广义Fibonacci数列找循环节 - HDU 5451 Best Solver

Best Solver Problem's Link Mean: 给出x和M,求:(5+2√6)^(1+2x)的值.x<2^32,M<=46337. analyse: 这题需要用到高中的数学知识点:特征根法求递推数列通项公式. 方法是这样的: 对于这题的解法: 记λ1=5+2√6,λ2=5-2√6,则λ1λ2=1,λ1+λ2=10 根据韦达定理可以推导出:λ1,λ2的特征方程为 x^2-10x+1=0 再使用该特征方程反向推导出递推公式为:a[n]=10*a[n-1]-a[n-2] 再由特征根

Linux学习资料-基础正规表示法(grep)

基础正规表示法:   -------------------------------------------------------------------------------- grep 语法: [root @test /root ]# grep [-acinv] '搜寻字符串' filename 参数说明: -a :将 binary 档案以 text 档案的方式搜寻数据 -c :计算找到 '搜寻字符串' 的次数 -i :忽略大小写的不同,所以大小写视为相同 -n :顺便输出行号 -v :