码迷,mamicode.com
首页 > 其他好文 > 详细

DTOJ #3316. baka

时间:2019-08-10 09:38:31      阅读:71      评论:0      收藏:0      [点我收藏+]

标签:sign   char   dfs   范围   get   整数   个数   getch   oid   

【题目描述】

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

【输入格式】

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

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

【输出格式】

一行一个数表示答案。

【样例】

样例输入
4
2 1
3 1
4 1

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

对于 $100\%$ 的数据,$1\leq n\leq 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\n",min(min(f[1][0][0],f[1][0][1]),min(f[1][1][0],f[1][1][1])));
}

 

DTOJ #3316. baka

标签:sign   char   dfs   范围   get   整数   个数   getch   oid   

原文地址:https://www.cnblogs.com/RenSheYu/p/11330275.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!