GVKun编程网logo

hdu-5834 Magic boy Bi Luo with his excited tree 树形dp(the boy saw the man with a telescope树形图)

4

对于hdu-5834MagicboyBiLuowithhisexcitedtree树形dp感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解theboysawthemanwithatelesc

对于hdu-5834 Magic boy Bi Luo with his excited tree 树形dp感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解the boy saw the man with a telescope树形图,并且为您提供关于C. Ilya And The Tree 树形dp 暴力、CCPC 2017 哈尔滨 L. Color a Tree && HDU 6241(二分+树形DP)、cf 627 F. Maximum White Subtree【树形dp】、Codeforces 1092F Tree with Maximum Cost(树形DP)的宝贵知识。

本文目录一览:

hdu-5834 Magic boy Bi Luo with his excited tree 树形dp(the boy saw the man with a telescope树形图)

hdu-5834 Magic boy Bi Luo with his excited tree 树形dp(the boy saw the man with a telescope树形图)

http://acm.hdu.edu.cn/showproblem.php?pid=5834

神级烦的一个树形dp

dp1【0】【x】代表从x结点向下走并且回到x结点的最大值

dp1【1】【x】代表从x结点向下走,并且不回到x结点的最大值(去向某一个子树分支,通过index【x】记录)

dp1【1】【x】代表从x结点向下走,并且不回到x结点的第二大值

dp2【0】【x】代表从x结点向父节点走,并且回来的最大值

dp2【1】【x】代表从x结点向父节点走,并且不回来的最大值



dp1【0】,每个子结点走下去在回来
dp1【1】选一个子结点走下去不回来,其余走下去回来
dp1【2】同上

dp2【0】走到父节点fa之后,去向父父结点再回来,再去向父节点的非自己子节点(兄弟结点)再回来
dp2【1】走到父节点fa之后,去向父父结点再回来,再去向父节点的非自己子节点(兄弟结点)不回来,选一个兄弟结点走下去(这里就会用到dp1【2】,当index【fa】等于自己时)
或者去向父节点的非自己子节点(兄弟结点)回来,再去向父父结点不回来


很啰嗦,很烦,wa了很多发QAQ

带了几个调试时举得样例

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
const int inf=0x3f3f3f3f;
long long dp1[3][maxn];
long long index[maxn];
long long dp2[2][maxn];
long long ans[maxn];
struct node
{
    int ne,cost;
};
int n;
int v[maxn];
vector<node>w[maxn];

void dfs1(int x,int fa)
{
	dp1[0][x]=v[x];
    for(int i=0;i<w[x].size();i++)
    {
        node ne=w[x][i];
        if(ne.ne==fa)
            continue;
        dfs1(ne.ne,x);
        if(dp1[0][ne.ne]-2*ne.cost>0)
        dp1[0][x]+=dp1[0][ne.ne]-2*ne.cost;
    }
    dp1[2][x]=dp1[1][x]=dp1[0][x];
    for(int i=0;i<w[x].size();i++)
    {
    	node ne=w[x][i];
    	if(ne.ne==fa)
    		continue;
    	int Now=dp1[0][x]-max(dp1[0][ne.ne]-2*ne.cost,0ll)+dp1[1][ne.ne]-ne.cost;
    	if(Now>=dp1[1][x])
    	{
    		dp1[2][x]=dp1[1][x];
    		index[x]=ne.ne;
    		dp1[1][x]=Now;
		}
		else if(Now>=dp1[2][x])
		{
			dp1[2][x]=Now;
		}
	}
}
void dfs2(int x,int fa)
{
    int i,k;
    for(i=0;i<w[x].size();i++)
    {
        node ne=w[x][i];
        if(ne.ne==fa)
            continue;
        int self=dp1[0][ne.ne]-2*ne.cost;
        if(self<0)
        self=0;
    	dp2[0][ne.ne]=max(dp2[0][ne.ne],dp1[0][x]-self+dp2[0][x]-2*ne.cost);
		if(ne.ne==index[x])
		{
			dp2[1][ne.ne]=max(dp2[1][ne.ne],dp2[0][x]-ne.cost+dp1[2][x]-self);
		}
		else
		{
			dp2[1][ne.ne]=max(dp2[1][ne.ne],dp2[0][x]-ne.cost+dp1[1][x]-self);
		}
		dp2[1][ne.ne]=max(dp2[1][ne.ne],dp1[0][x]-self+dp2[1][x]-ne.cost);
		dfs2(ne.ne,x);
	}
}

int main()
{
    int tca=1,T,i;
    cin>>T;
    while(T--)
    {
      	scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&v[i]);
        }
        int u1,u2,c;
        for(i=1;i<n;i++)
        {
            scanf("%d %d %d",&u1,&u2,&c);
            node tt;
            tt.ne=u2;
            tt.cost=c;
            w[u1].push_back(tt);
            tt.ne=u1;
            w[u2].push_back(tt);
        }
        printf("Case #%d:\n",tca++);
        for(i=0;i<=n;i++)
        dp1[0][i]=dp1[1][i]=dp1[2][i]=dp2[0][i]=dp2[1][i]=0,index[i]=-1;

  /*      node tt;
        tt.ne=1;
        v[0]=0;
        tt.cost=0;
        w[0].push_back(tt);
		dfs1(0,0);
        dfs2(0,0);*/
        dfs1(1,0);
        dfs2(1,0);
        for(i=1;i<=n;i++)
        {
   //         cout<<dp1[0][i]<<" "<<dp1[1][i]<<" "<<dp2[0][i]<<" "<<dp2[1][i]<<endl;
            printf("%d\n",max(dp1[0][i]+dp2[1][i],dp1[1][i]+dp2[0][i]));
        }
        for(i=0;i<=n;i++)
        w[i].clear();
    }
    return 0;
}
/*

5
2 6 3 3 4
1 2 5
1 3 1
1 4 4
1 5 2


5
3 3 3 3 3
1 2 1
1 3 1
1 4 1
1 5 1


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

*/

C. Ilya And The Tree 树形dp 暴力

C. Ilya And The Tree 树形dp 暴力

C. Ilya And The Tree

写法还是比较容易想到,但是这么暴力的写法不是那么的敢写。

就直接枚举了每一个点上面的点的所有的情况,对于这个点不放进去特判一下,然后排序去重提高效率。

注意dp[v]一开始存的是从根节点到这个节点都选的情况,这样才好往后转移。

分享图片

分享图片

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 4e5 + 10;
typedef long long ll;
int dp[maxn],head[maxn],cnt = 0,a[maxn];
vector<int>vec[maxn];
struct node
{
    int u,v,nxt;
    node(int u=0,int v=0,int nxt=0):u(u),v(v),nxt(nxt){}
}ex[maxn];

void init()
{
    memset(head,-1,sizeof(head));
    cnt = 0;
}
void add(int u,int v)
{
    ex[cnt] = node(u,head[u]);
    head[u] = cnt++;
    ex[cnt] = node(v,u,head[v]);
    head[v] = cnt++;
}

int gcd(int a,int b)
{
    return b == 0 ? a : gcd(b,a%b);
}

void dfs(int u,int pre)
{
    for(int i=head[u];i!=-1;i=ex[i].nxt)
    {
        int v = ex[i].v;
        if (v == pre) continue;
        dp[v] = gcd(dp[u],a[v]);
        vec[v].push_back(dp[u]);
        for(int j=0;j<vec[u].size();j++) vec[v].push_back(gcd(vec[u][j],a[v]));
        sort(vec[v].begin(),vec[v].end());
        vec[v].erase(unique(vec[v].begin(),vec[v].end()),vec[v].end());
        dfs(v,u);
    }
}

int main()
{
    init();
    int n;
    scanf("%d",&n);
    for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    dp[1] = a[1];
    vec[1].push_back(0);
    dfs(1,-1);
    for (int i = 1; i <= n; i++) dp[i] = max(dp[i],vec[i].back());
    for (int i = 1; i <= n; i++) printf("%d ",dp[i]);
    return 0;
}
View Code

CCPC 2017 哈尔滨 L. Color a Tree && HDU 6241(二分+树形DP)

CCPC 2017 哈尔滨 L. Color a Tree && HDU 6241(二分+树形DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6241

题意:给你一棵有 n 个结点的树,每个结点初始颜色都为白色,有 A 个条件:结点 x_i 的黑色结点数目不少于 y_i 个,同时有 B 个条件,除了结点 x_j 及其子树外至少有 y_j 个结点,求把最少要染成黑色结点的数目使得满足 A + B 个条件。

题解:参考自:https://blog.csdn.net/u013534123/article/details/78523559

 

 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define pII pair<ll,ll>
#define pi acos(-1)
#define pb push_back
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e5 + 10;
const int MAXM = 1e6 + 10;

int n;
vector<int>vec[MAXN];
int siz[MAXN],b[MAXN],mn[MAXN],mx[MAXN];
int up[MAXN],down[MAXN];

void init() {
    for(int i = 0; i <= n; i++) {
        vec[i].clear();
        b[i] = mn[i] = 0;
    }
}

void getsize(int u,int fa) {
    siz[u] = 1;
    for(int i = 0; i < vec[u].size(); i++) {
        int v = vec[u][i];
        if(v == fa) continue;
        getsize(v,u);
        siz[u] += siz[v];
    }
}

bool dfs(int u,int fa) {
    int l = 0, r = 1;
    for(int i = 0; i < vec[u].size(); i++) {
        int v = vec[u][i];
        if(v == fa) continue;
        if(!dfs(v,u)) return false;
        l += down[v], r += up[v];
    }
    down[u] = max(l, mn[u]), up[u] = min(r, mx[u]);
    return down[u] <= up[u];
}

bool check(int x) {
    for(int i = 1; i <= n; i++) {
        mx[i] = min(x - b[i],siz[i]);
        if(mx[i] < 0) return false;
    }
    return dfs(1,0) && down[1] <= x && x <= up[1];
}


int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
#endif
    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        init();
        for(int i = 1; i < n; i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            vec[u].pb(v);
            vec[v].pb(u);
        }
        getsize(1,0);
        int m;
        bool flag = true;
        scanf("%d",&m);
        while(m--) {
            int x,y;
            scanf("%d%d",&x,&y);
            mn[x] = max(mn[x],y);
            if(y > siz[x]) flag = false;
        }
        scanf("%d",&m);
        while(m--) {
            int x,y;
            scanf("%d%d",&x,&y);
            b[x] = max(b[x],y);
            if(y > n - siz[x]) flag = false;
        }
        if(!flag) {
            puts("-1");
            continue;
        }
        int l = 0, r = n, ans = -1;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(check(mid)) ans = mid, r = mid - 1;
            else l = mid + 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

cf 627 F. Maximum White Subtree【树形dp】

cf 627 F. Maximum White Subtree【树形dp】

 

 

 

 

 

 

 

 

 

思路

  令黑点点权为 -1 , 白点点权为 1,求最大子树点权和。

  设 f[i] 为包含 i 点的最大子树点权值,如果当前点的最大点权和  比  当前点父亲的最大点权和小, 则更新当前点。

  比较蠢的做法是,分两种情况讨论下,当前点的点权和 大于 或 小于 0 的情况处理是不同的。

  如果当前点子树权值 >= 0,且父亲的子树权值更大,应该把父亲点的子树归并到当前点的子树中。

  如果当前点子树权值  <  0,且父亲的子树中白的比黑的多,就把父亲点的子树归并到当前点子树上。

 

CODE

 

#include  < bits/stdc++.h >
#define  dbg ( x ) cout  << #x  <<  " = "  << x  << endl
#define  eps  1e - 8
#define  pi  acos ( - 1.0 )

using  namespace  std ;
typedef  long  long LL ;

const  int inf  =  0x3f3f3f3f ;

template < class  T > inline  void  read ( T  & res )
{
     char c ;T flag = 1 ;
     while ((c = getchar ()) < '' 0 '' ||c > '' 9 '' ) if (c == '' - '' )flag =- 1 ;res =c - '' 0 '' ;
     while ((c = getchar ()) >= '' 0 '' &&c <= '' 9 '' )res =res * 10 +c - '' 0 '' ;res *=flag ;
}

namespace  _buff  {
     const  size_t BUFF  =  1  <<  19 ;
     char  ibuf [BUFF ],  *ib  = ibuf ,  *ie  = ibuf ;
     char  getc ()  {
         if  (ib  == ie )  {
            ib  = ibuf ;
            ie  = ibuf  +  fread (ibuf ,  1 , BUFF , stdin );
         }
         return ib  == ie  ?  - 1  :  *ib ++ ;
     }
}

int  qread ()  {
     using  namespace  _buff ;
     int ret  =  0 ;
     bool pos  =  true ;
     char c  =  getc ();
     for  (;  (<  '' 0 ''  || c  >  '' 9 '' )  && c  !=  '' - '' ; c  =  getc ())  {
         assert ( ~c );
     }
     if  (==  '' - '' )  {
        pos  =  false ;
        c  =  getc ();
     }
     for  (; c  >=  '' 0 ''  && c  <=  '' 9 '' ; c  =  getc ())  {
        ret  =  (ret  <<  3 )  +  (ret  <<  1 )  +  (^  48 );
     }
     return pos  ? ret  :  -ret ;
}

const  int maxn  =  2e5  +  7 ;

int a [maxn ];
int n ;
int head [maxn  <<  1 ], edge [maxn  <<  1 ], nxt [maxn  <<  1 ], cnt ;
int f [maxn ];
bool vis [maxn ];
int ans [maxn ];

void  BuildGraph ( int  u ,  int  v )  {
    cnt ++ ;
    edge [cnt ]  = v ;
    nxt [cnt ]  = head [u ];
    head [u ]  = cnt ;
}

void  dfs ( int  u ,  int  fa )  {
     if (a [u ]  ==  1 )  {
         f [u ]  =  1 ;
     }
     else  {
         f [u ]  =  - 1 ;
     }
    //printf("f[%d]:%d\n",u, f[u]);
     for  (  int i  = head [u ]; i ; i  = nxt [i ]  )  {
         int v  =  edge [i ];
         if (== fa )
             continue ;
         else  {
             dfs (v , u );
             if ( f [v ]  >  0 )  {
                 f [u ]  +=  f [v ];
                //printf("f[%d]:%d\n",u, f[u]);
             }
         } 
     }
}

void  dp ( int  u ,  int  fa )  {
     if (f [u ]  >=  0 )  {
         int temp  =  f [fa ]  -  f [u ];
         if (temp  >=  0 )  {
             f [u ]  += temp ;
            //printf("f[%d]:%d\n",u, f[u]);
         }
     }
     else  {
        //printf("fa: f[%d]:%d\n",fa, f[fa]);
         if ( f [fa ]  >=  0 )  {
             f [u ]  +=  f [fa ];
            //printf("f[%d]:%d\n",u, f[u]);
         }
     }
     for  (  int i  = head [u ]; i ; i  = nxt [i ]  )  {
         int v  =  edge [i ];
        //dbg(v);
         if (== fa )
             continue ;
         else  {
             dp (v , u );
         }
     }
}

int  main ()
{
     read (n );
     for  (  int i  =  1 ; i  <= n ;  ++)  {
         read ( a [i ]);
     }
     for  (  int i  =  1 ; i  < n ;  ++)  {
         int u , v ;
         read (u );
         read (v );
         BuildGraph (u , v );
         BuildGraph (v , u );
     }
     dfs ( 1 ,  1 );
     dp ( 1 ,  1 );
     for  (  int i  =  1 ; i  <= n ;  ++)  {
         printf ( "%d   " , f [i ]);
     }
     return  0 ;
}

Codeforces 1092F Tree with Maximum Cost(树形DP)

Codeforces 1092F Tree with Maximum Cost(树形DP)

题目链接:Tree with Maximum Cost

题意:给定一棵树,树上每个顶点都有属性值ai,树的边权为1,求$\sum\limits_{i = 1}^{n} dist(i, v) \cdot a_i$,$dist(i, v) $为顶点i到顶点v的距离。该顶点v可以任意选择。

题解:O(n^2)的做法:从每个顶点跑一遍DFS,计算贡献值,并更新答案。(超时)

我们可以先计算出从顶点1跑的答案,发现顶点之间贡献的转移为$ans[u]=ans[fa]+(all-sum[u])-sum[u]$。(all为$\sum\limits_{i = 1}^{n} a_i$)

该顶点的上半部分贡献值增加(all-sum[u]),下半部分贡献值减少(sum[u])。

 1 #include <set>
 2 #include <map>
 3 #include <queue>
 4 #include <deque>
 5 #include <stack>
 6 #include <cmath>
 7 #include <cstdio>
 8 #include <vector>
 9 #include <string>
10 #include <cstring>
11 #include <fstream>
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 
16 #define eps 1e-8
17 #define pb push_back
18 #define PI acos(-1.0)
19 #define INF 0x3f3f3f3f
20 #define clr(a,b) memset(a,b,sizeof(a)
21 #define bugc(_) cerr << (#_) << " = " << (_) << endl
22 #define FAST_IO ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
23 
24 const int N=2e5+10;
25 typedef long long ll;
26 typedef unsigned long long ull;
27 ll a[N],sum[N],res,cnt,ans[N];
28 
29 vector <int> E[N];
30 
31 void dfs(int u,int fa,ll len){
32     res+=len*a[u];
33     sum[u]=a[u];
34     for(int i=0;i<E[u].size();i++){
35         int v=E[u][i];
36         if(v==fa) continue;
37         dfs(v,u,len+1);
38         sum[u]+=sum[v];
39     }
40 }
41 
42 void DFS(int u,int fa){
43     if(fa!=0) ans[u]=ans[fa]+cnt-2*sum[u];
44     for(int i=0;i<E[u].size();i++){
45         int v=E[u][i];
46         if(v==fa) continue;
47         DFS(v,u);
48     }
49 }
50 
51 int main(){
52     FAST_IO;
53     int n;
54     cin>>n;
55     for(int i=1;i<=n;i++) cin>>a[i],cnt+=a[i];
56     for(int i=1;i<n;i++){
57         int u,v;
58         cin>>u>>v;
59         E[u].push_back(v);
60         E[v].push_back(u);
61     }
62     dfs(1,0,0);
63     ans[1]=res;
64     DFS(1,0);
65     cout<<*max_element(ans+1,ans+1+n)<<endl;
66     return 0;
67 }
View Code

 

我们今天的关于hdu-5834 Magic boy Bi Luo with his excited tree 树形dpthe boy saw the man with a telescope树形图的分享就到这里,谢谢您的阅读,如果想了解更多关于C. Ilya And The Tree 树形dp 暴力、CCPC 2017 哈尔滨 L. Color a Tree && HDU 6241(二分+树形DP)、cf 627 F. Maximum White Subtree【树形dp】、Codeforces 1092F Tree with Maximum Cost(树形DP)的相关信息,可以在本站进行搜索。

本文标签:

上一篇Bi-Weekly | Amazon和Microsoft推出新的Gluon;Google的学习算法正创建另一(amazon and google)

下一篇HDU - 5834 Magic boy Bi Luo with his excited tree 树形dp 好题~