zoukankan      html  css  js  c++  java
  • 【中山市选2009】树

    【中山市选2009】树

    描述

    Description

      图论中的树为一个无环的无向图。给定一棵树,每个节点有一盏指示灯和一个按钮。如果节点的按扭被按了,那么该节点的灯会从熄灭变为点亮(当按之前是熄灭的),或者从点亮到熄灭(当按之前是点亮的)。并且该节点的直接邻居也发生同样的变化。
      开始的时候,所有的指示灯都是熄灭的。请编程计算最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。

    Input

      输入文件有多组数据。
      输入第一行包含一个整数n,表示树的节点数目。每个节点的编号从1到n。
      输入接下来的n – 1行,每一行包含两个整数x,y,表示节点x和y之间有一条无向边。
      当输入n为0时,表示输入结束。

    Output

      对于每组数据,输出最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。每一组数据独占一行。

    Sample Input

    3
    1 2
    1 3
    0

    Sample Output

    1

    Hint

    【数据规模】
      对于20%的数据,满足1 <= n <=15。
      对于40%的数据,满足1 <= n <=50。
      对于100%的数据,满足1 <= n <=100。


    做题过程

    这是一棵树,所以一眼看下去,马上想到树形DP。
    我推了一个方程,打了出来。后来读题时感到不对劲,发现我将那些操作看成覆盖了。
    我又推了一遍方程,于是AC了。

    分析

    这就是一道很水的树形DP。
    fifa表示i被父亲点亮时按的最少按钮
    fiso表示i被儿子点亮时按的最少按钮
    fise表示i被自己点亮时按的最少按钮
    ji的儿子
    对于fifa,它的儿子不能将它点亮,所以有偶数个儿子点亮了自己

    fifa=minfjse+fjso

    对于fiso,它的儿子要将它点亮,所以有奇数个儿子点亮了自己
    fiso=minfjse+fjso

    对于fise,它点亮了儿子,所以它的儿子都应被它点亮
    fise=1+fjfa

    这就是状态转移方程了。
    初始化:
    fifa=fiso=fise=1

    但是,用普通方法求fifafiso是很慢的。
    不妨转换一下式子
    fifa=minfjso+fjsefjsofiso=minfjso+fjsefjso

    显然左边是固定的,我们要让右边的值最小
    很简单的一个想法就是排序,然后按偶或奇个数选出最小值就行了。
    FQY大佬处理这个东西时用DP,厉害了!
    答案为minfrootso,frootse


    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int n;
    struct EDGE
    {
        int to;
        EDGE* las;
    } e[201];
    EDGE *last[101];
    struct Status
    {
        long long fa,so,se;//father,son,self
    } f[101];
    int a[101][107];
    int na[101];
    bool cmp(int x,int y)
    {
        return f[x].se-f[x].so<f[y].se-f[y].so;
    }
    void dp(int,int);
    int main()
    {
        int i,j,x,y;
        for (scanf("%d",&n);n;scanf("%d",&n))
        {
            memset(last,0,sizeof last);
            j=0;
            for (i=1;i<n;++i)
            {
                scanf("%d %d",&x,&y);
                last[x]=&(e[++j]={y,last[x]});
                last[y]=&(e[++j]={x,last[y]});
            }
            memset(na,0,sizeof na);
            dp(1,0);
            printf("%lld
    ",min(f[1].so,f[1].se));
        }
        return 0;
    }
    void dp(int x,int fa)
    {
        f[x].se=1;
        long long sum_so=0;
        EDGE *ei;
        for (ei=last[x];ei;ei=ei->las)
            #define son ei->to
            if (ei->to!=fa)
            {
                dp(son,x);
                a[x][++na[x]]=ei->to;//记录儿子,方便排序
                sum_so+=f[son].so;//记录总和
                f[x].se+=f[son].fa;//转移f[x].se
            }
        sort(a[x]+1,a[x]+na[x]+1,cmp);//排序
        int i;
        long long sum=0;
        f[x].fa=0x7f7f7f7f;
        for (i=0;i<=na[x];i+=2)//转移f[x].fa
        {
            f[x].fa=min(f[x].fa,sum_so+sum);
            sum+=f[a[x][i+1]].se-f[a[x][i+1]].so+f[a[x][i+2]].se-f[a[x][i+2]].so;
        }
        sum=f[a[x][1]].se-f[a[x][1]].so;
        f[x].so=0x7f7f7f7f;
        for (i=1;i<=na[x];i+=2)//转移f[x].so
        {
            f[x].so=min(f[x].so,sum_so+sum);
            sum+=f[a[x][i+1]].se-f[a[x][i+1]].so+f[a[x][i+2]].se-f[a[x][i+2]].so;
        }
    }
  • 相关阅读:
    hdu 1269 迷宫城堡 (并查集)
    hdu 1272 小希的迷宫 (深搜)
    hdu 1026 Ignatius and the Princess I (深搜)
    hdu 1099 Lottery
    hdu 1068 Girls and Boys (二分匹配)
    几个基础数位DP(hdu 2089,hdu 3555,uestc 1307 windy 数)
    hdu 1072 Nightmare (广搜)
    hdu 1398 Square Coins (母函数)
    hdu 1253 胜利大逃亡 (深搜)
    hdu 1115 Lifting the Stone (求重心)
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145296.html
Copyright © 2011-2022 走看看