Tree Tree [DP]

Tree (tree)


[Problems] Description
graph theory as a tree acyclic undirected graph. Given a tree, each node has an indicator and a button. If the button was pressed node, then the node from the lamp becomes lighted off (when the press is extinguished before), or from off to light up (when is lit before pressing). And the immediate neighbors of the same node also changes. Initially, all the lights are extinguished. Please programming to calculate how many times the minimum Yaoan button to make all the nodes of lights and lights up.
[Input format
input file multiple sets of data.
Input of the first row contains an integer n, the number of nodes of the tree. Each node are numbered from 1 to n.
Enter the next n - 1 rows, each containing two integers x, y, expressed an undirected edges between nodes x and y.
When the input n is 0, indicating the end of input.
[Output format]
For each test, the minimum number of times the output Yaoan button to make all the nodes of lights and lights up. Each set of data on a separate line.

Sample input:
. 3
1 2
1. 3
0
Output Sample:
1

This question reminds me of the inexplicable've seen a dead fat man with a finger on the letter will then point near to, but I forget the title of the ~ ~
Closer to home, the topic has been very clearly tell you were a tree, it can be very the tree is easy to think DP, looking for state transition equation is the key question.
First, we used f[x][0]to x as the root of sub-tree, the lights on x, while his son, grandson, son, grandson ... also turn on the lights in the minimum number of times;

And f[x][1]to x as the root of the subtree, x turn off the lights, and the minimum number of lights on his son's generation;

f[x][2]It is expressed in the sub-tree root node x, x turn off the lights, his son generation also turn off the lights of the minimum number of times;

So f[x][3]what is expressed, that is to x is the root of the sub-tree, x turn on the lights, the minimum number of his son's generation also turn off the lights, it is clear that it does not exist, so f[x][3]exclude it.

The definition of an array of F figured out, then the next will be easier!
Also in three steps:

  1. f[x][0]The best count, because if I and my generation sub-lights on, and then my friends and family do not have to turn on the lights, Whyf[x][0]+=f[x][2]

2. Even if the next f[x][2]and f[x][1]how to calculate it? Because we have to take into account the possible generation of my son by the odd press the button, the last state will change it (ps: What a boring son ..), so I need a variable to Count me by the way how many times (I call this variable button count). How then is "scientific shirk responsibility," and we have to use a variable to represent the minimum number, and that is tmp+=min(f[x][2],f[x][1])it!

3. f[x][2]和f[x][1]how to inherit it? That is green - Tibet - High - original, ah, say biased, and here that reflects our most most most lovely buttons counted (2:00 said, I do not know to re-read!), here I can tell you a skill, odd and even number is exactly the opposite, because the state is exactly the opposite thing, so you want to curious the next few directly to the odd reverse the order on the line, the odd then that f[x][2]=t, while the even word is f[x][1]=t, the rest I, I will not tell you, you first think, if you can not think of a direct look at the code it!

We will have found a state transition equation, followed by production of cataloging it, balabala, the whole questions to complete it!
Here I am attaching the code, the code is explained in detail:

#include<cmath>
#include<cstdio>
#include<cstring>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;//据说这个比long long更大,不过后面输出要用llu。
//你细心可以发现我跟本没用long long^_^ 
struct node//边目录 
{
    int x,y,next;//x和y表示一条边的两个端点,next表示下一条边的编号 
}a[210];int len,last[210];//last表示与当前边相连的最后一条边的编号,len是边的数目 
void ins(int x,int y)
{
    len++;//边的数目增加一条 
    a[len].x=x;a[len].y=y;//给边赋值 
    a[len].next=last[x];last[x]=len;//边的联系 
}
int f[210][3];//我们上面讲到的定义 
bool b[210];//因为我用的是双向边,而有可能会进入死循环 
void treeDP(int x)
{
    /*
    f[x][0]x开灯,开灯 
    f[x][1]x不开灯,开灯 
    f[x][2]x不开灯,不开灯 
    */
    f[x][0]=1;f[x][1]=f[x][2]=0;//一开始的以x为结点的子树(包括点x)全部开灯就有一种方法:点亮x
    //其他的归零 
    int minn=99999999,num=0,tmp=0;//这里的minn用的十分巧妙,num就是按钮计数,tmp就是存储最少次数 
    for(int k=last[x];k;k=a[k].next)//访问x的亲朋好友 
    {
        int y=a[k].y;//找到x点所在的边的另一个点y 
        if(b[y]==false)//判断是否找过y 
        {
            b[y]=true;treeDP(y);//标记找过,然后递归找y 
            f[x][0]+=f[y][2];//如果我和我的子辈都开着灯了,那么我的亲朋好友就不用开灯了啦! 
             
            tmp+=min(f[y][0],f[y][1]);//去最小的值 
            minn=min(abs(f[y][0]-f[y][1]),minn);//这里非常巧妙:
            /*假设f[y][0]>f[y][1]的话,那么此时tmp加的就是f[y][1],而minn里面的就是f[y][0]-f[y][1]
            那么tmp+minn实际上就是f[y][1]+f[y][0]-f[y][1]=f[y][0]
            而反之,tmp加的就是f[y][0],那么minn里面的就是f[y][1]-f[y][0]
            那么tmp+minn就是f[y][0]+f[y][1]-f[y][0]=f[y][1]了
            */ 
            if(f[y][1]>=f[y][0])num++;
            //如果不开灯比开灯要贵,那么我们肯定选开灯的,而此时就按了一次按钮,所以num++ 
        }
    }
    if(num%2==1)
    {
        f[x][2]=tmp+minn;//此时,x不开灯,而他的子辈也不开灯,就要让其中一个儿子帮他开灯 
        f[x][1]=tmp;//此时,x不开灯,要他的子辈开灯,那怎么无缘无故开灯呢?所以就让他的儿子去开灯 
    }
    else
    {
        f[x][2]=tmp;//同上,我说过是相反的 
        f[x][1]=tmp+minn;
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(f,0,sizeof(f));
        if(n==0)break;
        len=0;memset(last,0,sizeof(last));
        for(int i=1;i<n;i++)
        {
            int x,y;scanf("%d%d",&x,&y);
            ins(x,y);ins(y,x);
        }
        memset(b,false,sizeof(b));b[1]=true;
        treeDP(1);//从1开始递归,因为1是根节点 
        printf("%d\n",min(f[1][0],f[1][1]));//最后找这两个的最小值就行了! 
    }
    return 0;
}

Thank you for your watch, learn by analogy, you can do it on the tree caioj.cn Dynamic Programming 8 title Oh!

Guess you like

Origin www.cnblogs.com/candy067/p/11401969.html