• DTOJ #3316. baka


    【题目描述】

    给定一颗有方向的树,改变一条边方向的代价为 $1$,求使得从两个点出发能到达树上所有节点的最小代价。

    【输入格式】

    第一行一个正整数 $n$。

    接下来 $n-1$ 行,每行两个正整数 $u,v$,表示 $u$ 向 $v$ 连一条有向边。

    【输出格式】

    一行一个数表示答案。

    【样例】

    样例输入
    4
    2 1
    3 1
    4 1

    样例输出
    1
    【数据范围与提示】

    对于 $100\%$ 的数据,$1leq nleq 10^6]$。

    【题解】

    本题有两种思路。

    第一种,考虑到有两个起点,设 $f[i][1/2][0/1]$ 表示以 $i$ 为根的子树内已经有 $1/2$ 个出发点,$i$ 是否为出发点,直接转移即可。

    第二种,考虑到两个起点必然将整棵树分成两部分,考虑断边,换根 $dp$ 即可。

    【代码】

    #include<bits/stdc++.h>
    const int maxn=1000000+10;
    const int inf=1000000000;
    int n,f[maxn][2][2],g[2][2];
    std::vector<int> E[maxn],G[maxn];
    inline int read ( void )
    {
        int x=0;char ch;bool f=true;
        while ( !isdigit(ch=getchar()) ) if ( ch=='-' ) f=false;
        for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
        return f ? x : -x ;
    }
    using std::min;
    inline void dfs ( int u,int fr )
    {
        f[u][0][0]=f[u][1][0]=f[u][1][1]=inf;
        for ( int v:E[u] ) if ( v!=fr )
        {
            dfs(v,u);
            for ( int i=0;i<2;i++ ) for ( int j=0;j<2;j++ ) g[i][j]=f[u][i][j];
            f[u][0][0]=min(g[0][0]+f[v][0][1],g[0][1]+min(f[v][0][0],f[v][0][1])+1);
            f[u][0][1]=g[0][1]+f[v][0][1];
            f[u][1][0]=min(min(g[0][0]+min(min(f[v][0][0],f[v][1][1]),f[v][0][1]+1),g[0][1]+min(f[v][1][0],f[v][1][1])+1),min(g[1][0]+f[v][0][1],g[1][1]+min(f[v][0][0],f[v][0][1])+1));
            f[u][1][1]=min(g[1][1]+f[v][0][1],g[0][1]+min(f[v][1][1],f[v][0][0]));
        }
        for ( int v:G[u] ) if ( v!=fr )
        {
            dfs(v,u);
            for ( int i=0;i<2;i++ ) for ( int j=0;j<2;j++ ) g[i][j]=f[u][i][j];
            f[u][0][0]=min(g[0][0]+f[v][0][1]+1,g[0][1]+min(f[v][0][0],f[v][0][1]));
            f[u][0][1]=g[0][1]+f[v][0][1]+1;
            f[u][1][0]=min(min(g[0][0]+min(min(f[v][0][0],f[v][1][1]+1),f[v][0][1]+0),g[0][1]+min(f[v][1][0],f[v][1][1])+0),min(g[1][0]+f[v][0][1]+1,g[1][1]+min(f[v][0][0],f[v][0][1])));
            f[u][1][1]=min(g[1][1]+f[v][0][1],g[0][1]+min(f[v][1][1],f[v][0][0]))+1;
        }
    }
    signed main()
    {
        n=read();
        for ( int i=1,u,v;i<n;i++ ) u=read(),v=read(),E[u].push_back(v),G[v].push_back(u);
        dfs(1,0);
        return !printf("%d
    ",min(min(f[1][0][0],f[1][0][1]),min(f[1][1][0],f[1][1][1])));
    }
  • 相关阅读:
    C#,asp.net,命名空间名,类名,方法名的获得
    asp.net引用用户控件
    SQL数据是否存在(是否有数据)判断,表,存储过程是否存在
    asp:Button 事件,点击事件 html Button runat="sever"
    CSS图片最大大小限制
    asp.net 路径
    Js实现网站的重定向,Js转向网址,Js跳转
    ViewState 页面状态保留
    vs 附加到进程
    sql XML处理,sp_xml_preparedocument,openxml
  • 原文地址:https://www.cnblogs.com/RenSheYu/p/11330275.html
Copyright © 2020-2023  润新知