[CF 219D]Choosing Capital for Treeland[树形DP]

本文介绍了如何使用树形DP解决给定有向图中从一个点出发到其他所有点逆边数最小化的出发点及逆边数问题。通过递推方法,找出最优路径。

题意:

给出n个点, n-1条有向边, 问从一个点出发到其他所有点时, 使得逆的边数最小的出发点, 以及逆的边数. 有多个出发点的话升序输出.

思路:

树形DP.

这里DP的要义是一种递推, 只不过是沿着树的结构去递推.

有一个关系需要发现: 当知道一个点到其他所有点需要逆的边的条数之后, 其他各点的结果可以通过递推求出:

假设root有son1和son2, root到其他所有点, 都是先到son1, son2, 再接着往下走.

那么求son1到所有点的时候, son1到son1子树的计数情况和root的计数情况相同, son1到root之后再走son2子树的计数情况也和root相同. 于是只有son1到root之间一段不同.

如果是root->son1, 那么dp[son1] = dp[root] + 1; 否则dp[son1] = dp[root] - 1;

再dfs一遍即可.

#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 200005;
struct pool
{
    int v,w,next;
}g[MAXN<<1];
int head[MAXN],num,n;
int dp[MAXN],rt;
bool vis[MAXN];

void add(int u, int v)
{
    g[++num].v = v;
    g[num].w = 0;
    g[num].next = head[u];
    head[u] = num;
    g[++num].v = u;
    g[num].w = 1;
    g[num].next = head[v];
    head[v] = num;
}

void dfs1(int u)
{
    vis[u] = true;
    for(int i=head[u],v;i,v=g[i].v;i=g[i].next)
    {
        if(!vis[v])
        {
            rt += g[i].w;
            dfs1(v);
        }
    }
}

void dfs2(int u)
{
    vis[u] = true;
    for(int i=head[u],v;i,v=g[i].v;i=g[i].next)
    {
        if(!vis[v])
        {
            if(g[i].w)  dp[v] = dp[u] - 1;
            else dp[v] = dp[u] + 1;
            if(dp[v]<rt)    rt = dp[v],num = 1;
            else if(dp[v]==rt)  num++;
            dfs2(v);
        }
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        add(u,v);
    }
    dfs1(1);
    dp[1] = rt;
    memset(vis,false,sizeof(vis));
    num = 1;
    dfs2(1);
    printf("%d\n",rt);
    for(int i=1,cnt=0;i<=n;i++)
    {
        if(dp[i]==rt)   printf("%d%c",i,(++cnt==num)?'\n':' ');
    }
}


ollecting alphalens Using cached alphalens-0.4.0.tar.gz (24.0 MB) Preparing metadata (setup.py) ... error error: subprocess-exited-with-error × python setup.py egg_info did not run successfully. │ exit code: 1 ╰─> [26 lines of output] /tmp/pip-install-xgmte2ke/alphalens_c71a219d7adf4a65ae4a00db544ad00e/versioneer.py:564: SyntaxWarning: invalid escape sequence '\s' mo = re.search(r'=\s*"(.*)"', line) Traceback (most recent call last): File "<string>", line 2, in <module> exec(compile(''' ~~~~^^^^^^^^^^^^ # This is <pip-setuptools-caller> -- a caller that pip uses to run setup.py ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...<32 lines>... exec(compile(setup_py_code, filename, "exec")) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ''' % ('/tmp/pip-install-xgmte2ke/alphalens_c71a219d7adf4a65ae4a00db544ad00e/setup.py',), "<pip-setuptools-caller>", "exec")) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "<pip-setuptools-caller>", line 35, in <module> File "/tmp/pip-install-xgmte2ke/alphalens_c71a219d7adf4a65ae4a00db544ad00e/setup.py", line 35, in <module> version=versioneer.get_version(), ~~~~~~~~~~~~~~~~~~~~~~^^ File "/tmp/pip-install-xgmte2ke/alphalens_c71a219d7adf4a65ae4a00db544ad00e/versioneer.py", line 1480, in get_version return get_versions()["version"] ~~~~~~~~~~~~^^ File "/tmp/pip-install-xgmte2ke/alphalens_c71a219d7adf4a65ae4a00db544ad00e/versioneer.py", line 1412, in get_versions cfg = get_config_from_root(root) File "/tmp/pip-install-xgmte2ke/alphalens_c71a219d7adf4a65ae4a00db544ad00e/versioneer.py", line 342, in get_config_from_root parser = configparser.SafeConfigParser() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: module 'configparser' has no attribute 'SafeConfigParser'. Did you mean: 'RawConfigParser'? [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. error: metadata-generation-failed × Encountered error while generating package metadata. ╰─> See above for output. note: This is an issue with the package mentioned above, not pip. hint: See above for details. 如何解决
最新发布
09-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值