zoukankan      html  css  js  c++  java
  • HZAU 1201 Friends(树形DP 待整理)

    1201: Friends

    Time Limit: 1 Sec  Memory Limit: 1280 MB
    Submit: 98  Solved: 16
    [Submit][Status][Web Board]

    Description

        In a country, the relationship between people can be indicated by a tree. If two people are acquainted with each other, there will be an edge between them. If a person can get in touch with another through no more than five people, we should consider these two people can become friends. Now, give you a tree of N people’s relationship. ( 1 <= N <= 1e5), you should compute the number of who can become friends of each people?  

    Input

        In the first line, there is an integer T, indicates the number of the cases.
        For each case, there is an integer N indicates the number of people in the first line.
       

    In the next N-1 lines, there are two integers u and v, indicate the people u and the people

    v are acquainted with each other directly. People labels from 1.  

    Output

        For each case, the first line is “Case #k :”, k indicates the case number.

        In the next N lines, there is an integer in each line, indicates the number of people who can become the ith person’s friends. i is from 1 to n.  

    Sample Input

    1 
    8 
    1 2 
    2 3 
    3 4 
    4 5 
    5 6 
    6 7 
    7 8
    
    

    Sample Output

    Case #1:
    6
    7
    7
    7
    7
    7
    7
    6
    

    HINT

    Source



    【题目大意】

      给出一棵树,问每个节点距离六个点以内的点有几个

     

    【题解】

      定根维护树形DP,Dw[x][i]数组表示从上往下到达的距离为i的点的个数,
      有Dw[x][i]=sum(Dw[son][i-1]),Up[x][i]表示从下往上距离为i的点的个数,
      有Up[x][i]=Up[fx][i-1]+Dw[fx][i-1]-Dw[x][i>=2?i-2:0],
      两边dfs计算出这两个值,就可以得到每个点的答案了。

    官解:(here

    •F[rt][len] :节点rt的子孙里,距离rt的为len的节点个数

    •ans[rt][len] : 整棵树上,距离rt为len的节点个数

    •F值一次简单的深搜可以得到

    •而ans[rt][len] = F[rt][len] + ans[fa(rt)][len – 1] – F[fa(rt)][len – 1]


    参考:here

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    using namespace std;
    const int N=100010;
    vector<int> v[N];
    int Dw[N][10],Up[N][10];
    void dfs(int x,int fx){
        Dw[x][0]=1;
        for(int i=0;i<v[x].size();i++)if(v[x][i]!=fx){
            dfs(v[x][i],x);
            for(int j=1;j<=6;j++)Dw[x][j]+=Dw[v[x][i]][j-1];
        }
    }
    void dfs2(int x,int fx){
        Up[x][0]=1;
        if(x!=fx){for(int i=1;i<=6;i++)Up[x][i]=Up[fx][i-1]+Dw[fx][i-1]-Dw[x][i>=2?i-2:0];}
        for(int i=0;i<v[x].size();i++)if(v[x][i]!=fx){dfs2(v[x][i],x);}
    }
    int T,n;
    int main(){
        scanf("%d",&T);
        for(int cas=1;cas<=T;cas++){
            printf("Case #%d:
    ",cas);
            scanf("%d",&n);
            for(int i=1;i<=n;i++)v[i].clear();
            memset(Dw,0,sizeof(Dw));
            memset(Up,0,sizeof(Up));
            for(int i=1;i<n;i++){
                int x,y;
                scanf("%d%d",&x,&y);
                v[x].push_back(y);
                v[y].push_back(x);
            }dfs(1,1); dfs2(1,1);
            for(int i=1;i<=n;i++){
                int res=0;
                for(int j=1;j<=6;j++)res=res+Up[i][j]+Dw[i][j];
                printf("%d
    ",res);
            }
        }return 0;
    }





    here

    /**
    Problem C Friends
    
    
    题意:给n个人,有n-1个朋友关系,形成一棵树,如果两个人能够通过不超过5个人可以联系到,那么那两个人也是朋友,问你每个人有多少个朋友,
    比如(1-2-3-4-5-6-7-8),1可以联系到2 3 4 5 6 7,所以1有6个朋友
    
    
    思路:先对树进行dfs搜索形成有向树,根节点为1(任意),在设son[o][i]表示以o为节点在通过恰好i个人联系可以成为朋友的个数,只计算在根为o的子树中
    的结果,那么设p1,p2,p3,p4,p5,p6为o的一级祖先、二级祖先、..六级祖先那么对于节点o来说, 
    
    
    不通过p1能成为朋友的个数为 sigma {son[o][i] | 0 <= i <= 6}, 计算的是包含o节点的
    
    
    不通过p2而通过p1能成为朋友的个数为 sigma {son[p1][i] | 0 <= i <= 5}
    但是这里再次计算了经过o的情况, 所以需要减去 sigma {son[p1][i] | 0 <= i <= 4}
    
    
    同理需要经过Pj祖先的时候, 总个数为 sigma {son[Pj][i] | 0 <= i <= 6 - j}
    但是不能再通过Pj-1, 所以减去 sigma {son[Pj-1][i] | 0 <= i <= 6 - j - 1}
    
    
    所有pj的结果加起来再减去1就是答案了, 因为把o节点自己计算了在内
    **/
    
    
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    const int maxn = 1e5 + 10;
    using namespace std;
    
    
    int T, n, kase = 1;
    int pre[maxn];
    vector<int> G[maxn];
    int son[maxn][7];
    int que[10];
    
    
    void dfs(int fa[7], int u) {
        int fat = fa[5];
        pre[u] = fat;
        for(int i = 0; i <= 5; i++) {
            int f = fa[i];
            son[f][6 - i]++;
        }
        int nf[7] = {fa[1], fa[2], fa[3], fa[4], fa[5], u};
        for(int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if(v == fat) continue;
            dfs(nf, v);
        }
    }
    
    
    int main() {
        scanf("%d", &T);
        while(T--) {
            scanf("%d", &n);
            memset(son, 0, sizeof son);
            for(int i = 0; i <= n; i++) {
                son[i][0] = 1;
                G[i].clear();
                for(int j = 1; j < 7; j++) son[i][j] = 0;
            }
            for(int i = 1; i < n; i++) {
                int u, v;
                scanf("%d %d", &u, &v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
            int f[7] = {0, 0, 0, 0, 0, 0};
            dfs(f, 1);
            printf("Case #%d:
    ", kase++);
            for(int i = 1; i <= n; i++) {
                int ans = 0;
                for(int j = 0; j <= 6; j++) ans += son[i][j];
                int u = i;
                for(int j = 1; j <= 6; j++) {
                    int v = u; u = pre[u];
                    if(u == 0) break;
                    for(int k = 0; k <= 6 - j; k++) ans += son[u][k];
                    for(int k = 0; k <= 6 - j - 1; k++) ans -= son[v][k];
                }
                
                printf("%d
    ", ans - 1);
            }
        }
        return 0;
    }
    

  • 相关阅读:
    [LeetCode] Add and Search Word
    [LintCode] Delete Digits
    [LintCode] Number of Airplanes in the Sky
    [LintCode] Subarray Sum Closest
    [LeetCode] Course Schedule II
    [LeetCode] Minimum Size Subarray Sum
    [LeetCode] Implement Trie (Prefix Tree)
    [Leetcode] Course Schedule
    [hihoCoder] 博弈游戏·Nim游戏
    [hihoCoder] #1055 : 刷油漆
  • 原文地址:https://www.cnblogs.com/zswbky/p/6792889.html
Copyright © 2011-2022 走看看