现在的位置: 首页 > 综合 > 正文

Codeforces #135 T4 Choosing Capital for Treeland

2017年04月28日 ⁄ 综合 ⁄ 共 1127字 ⁄ 字号 评论关闭

http://blog.csdn.net/acm_ted/article/details/7922132

题意:给你一个有向的树,让你选择一个点使得通过反向一些边让这点能到所以其他的点,同时让需要反向的边最少。

题解:两次树形DP,第一次求子树需要反向的边,第二次累加父树以上需要反向的边,取和的最小值即为答案。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 200005
int edge[MAX<<1];//表示第i条边的终点
int next[MAX<<1];//与第i条边同起点的下一条边的位置
int head[MAX<<1];//以i为起点的第一条边的储存位置
int to[MAX<<1];
int dp[MAX],dpx[MAX];
void insert(int i,int a,int b,int c)//a起点,b终点
{
    edge[i]=b;
    next[i]=head[a];
    to[i]=c;
    head[a]=i;
}
void dfs_f(int x,int p)//统计子树的修改次数
{
    dp[x]=0;
    for(int i=head[x];i!=-1;i=next[i])
    {
        int k=edge[i];
        if(k==p) continue;
        dfs_f(k,x);
        dp[x]+=(dp[k]+(to[i]==x));
    }
}
void dfs_m(int x,int p,int idx)
{
    if(p==-1) dpx[x]=dp[x];
    else
    {
        if(to[idx]==x) dpx[x]=dpx[p]+1;
        else           dpx[x]=dpx[p]-1;
    }
    for(int i=head[x];i!=-1;i=next[i])
    {
        int k=edge[i];
        if(k==p) continue;
        dfs_m(k,x,i);
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    memset(next,-1,sizeof(next));
    int n,a,b;
    scanf("%d",&n);
    for(int i=1,j=1;i<n;++i)
    {
        scanf("%d%d",&a,&b);
        insert(j++,a,b,b);
        insert(j++,b,a,b);
    }
    dfs_f(1,-1);
    dfs_m(1,-1,1);
    int maxx=0xfffff;
    for(int i=1;i<=n;++i)
        if(dpx[i]<maxx) maxx=dpx[i];
    printf("%d\n",maxx);
    for(int i=1;i<=n;++i)
        if(dpx[i]==maxx)
           printf("%d ",i);
    return 0;
}

抱歉!评论已关闭.