zoukankan      html  css  js  c++  java
  • 【HDU 1054】Strategic Game【树形DP】

    题目大意:

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1054
    给出一棵树,树的每一条边左右两个点至少得有一个点被选择。求选择的最小数量。


    思路:

    很明显的树形DP。和没有上司的舞会很像。
    对于每一个点,如果选择它,那么它的子节点就可以选择,也可以不选择,那么选择它的最优答案就是它的子节点选择或不选择的最优答案之和。
    那么如果不选择这个点,那么它的所有子节点都必须选择,所以答案就是它的所有子节点被选择的最优答案之和。
    f[x][1]f[x][1]为选择点xx的最优答案,f[x][0]f[x][0]为不选择点xx的最优答案,那么就有(yyxx的子节点):
    f[x][1]=i=1m[x]min(f[y[i]][1],f[y[i]][0])f[x][1]=\sum^{m[x]}_{i=1}min(f[y[i]][1],f[y[i]][0])
    f[x][0]=i=1m[x]f[y[i]][1]f[x][0]=\sum^{m[x]}_{i=1}f[y[i]][1]


    代码:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #define N 20010
    using namespace std;
    
    int n,m,x,y,k,root,f[N][2],head[N],out[N];
    char c;
    bool Root[N];
    
    struct edge
    {
        int to,next;
    }e[N];
    
    void add(int from,int to)
    {
        k++;
        e[k].to=to;
        e[k].next=head[from];
        head[from]=k;
    }
    
    void dp(int x,int fa)
    {
    	int ans1=0,ans2=0;
    	if (!out[x]) return;
        for (int i=head[x];~i;i=e[i].next)  //找这个点的所有子节点
        {
            int v=e[i].to;
            if (v==fa) continue;
            dp(v,x);
            ans1+=min(f[v][1],f[v][0]);
            ans2+=f[v][1];
        }
        f[x][1]=ans1+1;
        f[x][0]=ans2;
    }
    
    int main()
    {
        while (cin>>n)
        {
            memset(Root,0,sizeof(Root));
            memset(f,0x3f3f3f3f,sizeof(f));
            memset(out,0,sizeof(out));
            memset(head,-1,sizeof(head));
            memset(e,0,sizeof(e));
            k=0;
            for (int i=1;i<=n;i++)
            {
                cin>>x>>c>>c>>m>>c;  //这道题拥有者神奇的读入
                x++;
                for (int j=1;j<=m;j++)
                {
                    scanf("%d",&y);
                    y++;
                    add(x,y);
                    add(y,x);
                    Root[y]=true;  //点y不可能是根节点
                    out[x]++;  //x的出度
                }
            }
            for (int i=1;i<=n;i++)
            {
                if (!Root[i]) root=i;  //是根节点
                if (!out[i])   //是叶子节点
                {
                    f[i][1]=1;
                    f[i][0]=0;
                }
            } 
            dp(root,-233);
            printf("%d\n",min(f[root][0],f[root][1]));
        }
        return 0;
    }
    
  • 相关阅读:
    Codeforces 691A Fashion in Berland
    HDU 5741 Helter Skelter
    HDU 5735 Born Slippy
    HDU 5739 Fantasia
    HDU 5738 Eureka
    HDU 5734 Acperience
    HDU 5742 It's All In The Mind
    POJ Euro Efficiency 1252
    AtCoder Beginner Contest 067 C
    AtCoder Beginner Contest 067 D
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998610.html
Copyright © 2011-2022 走看看