• 树形DP


     ① 相邻节点不能同时选时

      所得到权值最大:POJ2342 

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <math.h>
     5 #define SIGMA_SIZE 26
     6 #pragma warning ( disable : 4996 )
     7 
     8 using namespace std;
     9 typedef long long LL;
    10 
    11 inline int Max(int a,int b) { return a>b?a:b; }
    12 inline int Min(int a,int b) { return a>b?b:a; }
    13 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    14 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    15 const int inf = 0x3f3f3f3f;
    16 const int maxn = 6005;
    17 const int maxk = 2e6+5;
    18 
    19 
    20 
    21 int father[maxn], happy[maxn];
    22 bool vis[maxn];
    23 int dp[maxn][2];        //dp[i][0],dp[i][1]表示i不去或去产生的最大价值
    24 int N, R;
    25 
    26 int find( int r )
    27 {
    28     vis[r] = 1;
    29 
    30 
    31     for( int i = 1; i <= N; i++ )
    32         if ( !vis[i] && father[i] == r )
    33         {
    34             find(i);
    35             dp[r][1] += dp[i][0];
    36             dp[r][0] += Max(dp[i][1],dp[i][0]);
    37         }
    38     return Max( dp[r][1], dp[r][0] );
    39 } 
    40 
    41 void read()
    42 {
    43     memset( vis, 0, sizeof(vis) );
    44     cin >> N;
    45     int x, y;
    46 
    47     for ( int i = 1; i <= N; i++ )
    48         scanf( "%d", &happy[i] );
    49     for ( int i = 1; i < N; i++ )
    50     {
    51         scanf( "%d %d", &x, &y );
    52         father[x] = y;
    53         //son[y] = x;
    54         R = y;
    55     }
    56     cin >> x >> y;
    57 
    58     for( int i = 1; i <= N; i++ )
    59         dp[i][1] = happy[i];
    60 }
    61 
    62 
    63 int main()
    64 {
    65     read();
    66     
    67     cout << find(R) << endl;
    68 
    69     return 0;
    70 }
    View Code

      所得到权值最小:POJ1463,其实并不是最小..具体要求看题目

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <string>
     5 #include <math.h>
     6 #define SIGMA_SIZE 26
     7 #pragma warning ( disable : 4996 )
     8 
     9 using namespace std;
    10 typedef long long LL;
    11 
    12 inline int Max(int a,int b) { return a>b?a:b; }
    13 inline int Min(int a,int b) { return a>b?b:a; }
    14 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    15 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    16 const int inf = 0x3f3f3f3f;
    17 const int maxn = 2000;
    18 const int maxk = 2e6+5;
    19 
    20 int dp[maxn][2], father[maxn];
    21 int N, ans;
    22 bool vis[maxn];
    23 string road;
    24 
    25 int find( int r )
    26 {
    27     vis[r] = true;
    28 
    29     for ( int i = 0; i < N; i++ )
    30         if ( !vis[i] && father[i] == r )
    31         {
    32             find(i);
    33             dp[r][1] += Min( dp[i][0], dp[i][1] );
    34             dp[r][0] += dp[i][1];
    35         }
    36     return Min( dp[r][0], dp[r][1] );
    37 }
    38 
    39 void init()
    40 {
    41     ans = 0;
    42     memset( dp, 0, sizeof(dp) );
    43     memset( vis, 0, sizeof(vis) );
    44     memset( father, -1, sizeof(father) );
    45     
    46     int u, v, num;
    47     
    48     for ( int j = 1; j <= N; j++ )
    49     {
    50         scanf( "%d:(%d)", &u, &num );
    51         for ( ; num; num-- )
    52         {
    53             scanf("%d", &v);
    54             father[v] = u;
    55         }
    56     }
    57 
    58 
    59     for ( int i = 0; i < N; i++ )
    60         dp[i][1] = 1;
    61 }
    62 
    63 int main()
    64 {
    65     while ( ~scanf("%d", &N ) )
    66     {
    67         init();
    68         
    69         for ( int i = 0; i < N; i++ )
    70             if ( !(father[i]+1) ) 
    71                 ans += find(i);
    72 
    73         cout << ans << endl;
    74     }
    75     return 0;
    76 }
    View Code

       在基环树上取得的值最大: 基环树是指N个节点N条边的“树”,可见其上必然有环,但是删除环上任意一条边后可变成树,所以做法相比与上两题就是先求出环,把环所在的一条边删掉,再在树上做DP,这道题坑爹的是没说所有点是连通的,所以需要把答案加起来

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <queue>
      5 #include <math.h>
      6 #include <string>
      7 #include <map>
      8 #include <algorithm>
      9 #define SIGMA_SIZE 26
     10 #pragma warning ( disable : 4996 )
     11 
     12 using namespace std;
     13 typedef long long LL;
     14 
     15 inline int Max(int a,int b) { return a>b?a:b; }
     16 inline int Min(int a,int b) { return a>b?b:a; }
     17 inline LL LMax(LL a,LL b) { return a>b?a:b; }
     18 inline LL LMin(LL a,LL b) { return a>b?b:a; }
     19 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
     20 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
     21 const int inf = 0x3f3f3f3f;
     22 const int maxn = 1e6+5;
     23 const int maxk = 200;
     24 const int mod = 100000000;
     25 
     26 struct node {
     27     int next, to;
     28 }e[maxn<<1];
     29 
     30 int head[maxn], val[maxn];
     31 LL dp[2][maxn];
     32 bool vis[maxn];
     33 int cnt, N;
     34 int nopass, ringP1, ringP2;
     35 
     36 void addedge( int u, int v ) 
     37 {
     38     e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++;
     39     e[cnt].to = u; e[cnt].next = head[v]; head[v] = cnt++;
     40 }
     41 
     42 void init()
     43 {
     44     cnt = 0;
     45     memset( head, -1, sizeof(head) );
     46     memset( vis, 0, sizeof(vis) );
     47 }
     48 
     49 void getDp( int t, int pre )
     50 {
     51     dp[0][t] = 0; dp[1][t] = val[t];
     52     
     53     for ( int i = head[t]; i+1; i = e[i].next )
     54     {
     55         if ( e[i].to == pre ) continue;
     56         if ( i == nopass || i == (nopass^1) ) continue;
     57 
     58         getDp( e[i].to, t );
     59         dp[0][t] += LMax( dp[1][e[i].to], dp[0][e[i].to] );
     60         dp[1][t] += dp[0][e[i].to];
     61     }
     62 }
     63 
     64 void dfs( int t, int pre ) 
     65 {
     66     vis[t] = true;
     67 
     68     for ( int i = head[t]; i+1; i = e[i].next )
     69     {
     70         int tmp = e[i].to;
     71 
     72         if ( tmp == pre ) continue;
     73         if ( !vis[tmp] ) dfs( tmp, t );
     74         else
     75         {    //不是父亲,又没被遍历过,说明是环的一部分
     76             nopass = i;
     77             ringP1 = tmp; ringP2 = t; 
     78         }
     79     }
     80 }
     81 
     82 int main()
     83 {
     84     init();
     85     cin >> N;
     86 
     87     int x;
     88     for ( int i = 1; i <= N; i++ )
     89         { scanf("%d %d", &val[i], &x ); addedge(x,i); }
     90 
     91     LL tmp, ans = 0;
     92 
     93     for ( int i = 1; i <= N; i++ )
     94     {
     95         if (vis[i]) continue;
     96 
     97         dfs(i, -1);
     98         getDp( ringP1, -1 );
     99         tmp = dp[0][ringP1];
    100         
    101         getDp( ringP2, -1 );
    102         ans += LMax( tmp, dp[0][ringP2] );
    103     }
    104 
    105     printf("%lld
    ",ans);
    106     return 0;
    107 }
    View Code

    ② 去掉一个点

      POJ2378:去掉一个点后剩下的连通分量中节点个数小于等于N/2,问这样的点有多少个(感觉并没有dp啊...完全就是dfs嘛)

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <queue>
     5 #include <string>
     6 #include <algorithm>
     7 #define SIGMA_SIZE 26
     8 #pragma warning ( disable : 4996 )
     9 
    10 using namespace std;
    11 typedef long long LL;
    12 
    13 inline int Max(int a,int b) { return a>b?a:b; }
    14 inline int Min(int a,int b) { return a>b?b:a; }
    15 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    16 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    17 const int inf = 0x3f3f3f3f;
    18 const int maxn = 1e4+5;
    19 const int maxk = 2e6+5;
    20 
    21 struct node {
    22     int to, next;
    23 }e[2*maxn];
    24 
    25 int N, cnt;
    26 int sum[maxn], dp[maxn], linjie[maxn];
    27 //dp[i]表示去掉i后,i的儿子形成的连通分量中,最多的节点个数
    28 //sum[i]表示包括i及从i往下走的所有节点数
    29 bool vis[maxn];
    30 vector<int> ans;
    31 
    32 void addedges( int u, int v )
    33 {
    34     e[cnt].to = v; e[cnt].next = linjie[u]; linjie[u] = cnt++;
    35     e[cnt].to = u; e[cnt].next = linjie[v]; linjie[v] = cnt++;
    36 }
    37 
    38 int find( int r )
    39 {
    40     int tmp, v, mmax = 0;
    41     sum[r]++;
    42     vis[r] = true;
    43     
    44     for ( int i = linjie[r]; i+1; i = e[i].next )
    45         if ( !vis[e[i].to] )
    46         {
    47             v = e[i].to;
    48             tmp = find(v);
    49 
    50             mmax = Max(mmax, tmp);
    51             sum[r] += tmp;
    52         }
    53     dp[r] = mmax;
    54 
    55     if ( r != 1 )
    56         if ( dp[r] <= N/2 && N-sum[r] <= N/2 )
    57             ans.push_back(r);
    58 
    59     return sum[r];
    60 }
    61 
    62 void init()
    63 {
    64     cin >> N;
    65     cnt = 0;
    66     memset( vis, 0, sizeof(vis) );
    67     memset( linjie, -1, sizeof(linjie) );
    68 }
    69 
    70 int main()
    71 {
    72     init();
    73 
    74     int x, y;
    75     for ( int i = 1; i < N; i++ )
    76     {
    77         scanf( "%d %d", &x, &y );
    78         addedges(x,y);
    79     }
    80 
    81     find(1);
    82     if ( dp[1] <= N/2 )
    83         ans.push_back(1);
    84 
    85     sort( ans.begin(), ans.end() );
    86 
    87     if ( ans.empty() )
    88         cout << "NONE" << endl;
    89     else
    90         for ( vector<int>::iterator it = ans.begin(); it!=ans.end(); it++ )
    91             cout << (*it) << endl;
    92     return 0;
    93 }
    View Code
  • 相关阅读:
    C++入门经典-例4.9-输出不同生命周期的变量值
    C++入门经典-例4.8-同名的全局变量和局部变量
    C++入门经典-例4.7-变量的作用域
    C++入门经典-例4.6-使用重载函数
    C++入门经典-例4.5-利用循环求n的阶乘
    C++入门经典-例4.4-循环嵌套之求n的阶乘
    C++入门经典-例4.3-函数的递归调用之汉诺塔问题
    C++入门经典-例4.2-调用默认参数的函数
    C++入门经典-例4.1-声明、定义和使用函数
    C++入门经典-例3.25-使用循环输出闰年
  • 原文地址:https://www.cnblogs.com/chaoswr/p/8711512.html
Copyright © 2020-2023  润新知