zoukankan      html  css  js  c++  java
  • 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])));
    }
  • 相关阅读:
    使用SHA256WithRSA来签名和验签(.NET/C#)
    对2个hex(16进制)字符串进行异或操作
    Java DESede 加解密("DESede/ECB/PKCS5Padding")
    获取公钥证书的DN(Distinguished Name)
    Java DES 加解密("DES/EBC/NoPadding")
    Porting .Net RSA xml keys to Java
    Linux使用Shell脚本实现ftp的自动上传下载
    Lombok 安装、入门
    一段对16进制字符串进行异或的代码
    一个封装的使用Apache HttpClient进行Http请求(GET、POST、PUT等)的类。
  • 原文地址:https://www.cnblogs.com/RenSheYu/p/11330275.html
Copyright © 2011-2022 走看看