UVALive 5088 Alice and Bob's Trip(树形DP)

来源:互联网 发布:lv为什么那么贵 知乎 编辑:程序博客网 时间:2024/04/29 08:03

题目大意:给你一棵有n个点的树,根节点编号0,现在Alice 和 Bob要去旅行,Alice 想要边的和尽可能小,Bob想要尽量大,但是两个人都必须要使这个和在区间 [ l , r ],每人轮流选一条边,Bob 开始选,问你最大的和。

思路:树形DP,设d[ u ][ 0 ] 表示以u为根节点的子树,先有 Alice 选的最大和,d[ u ][ 1 ] 表示 Bob 先选的最大和,由于树中从根节点到任意一点的路径是唯一的,d[ u ][ 0 ] 获得的值其实是d[ u ][ 0 or 1 ] + dis(root , u),转移时要保证这个值要在 [ l ,  r ] 区间内,状态转移方程为 d[ u ][ 0 ] = min(d[ v ][ 1 ] + val( u, v )),d[ u ][ 1 ] = max(d[ v ][ 0 ] + val( u , v) ) ,同时满足前面说的区间的条件。

自己想的时候,状态表示、状态方程是挺简单的,可就是那个区间不好处理,我知道如果 d[ u ] > l 了,那么它就肯定不能去转移了,因为上面还有权值,那么 r 这里也不好处理,还有 就算 满足 d[ u ] <= l 了,也不能确定转移,因为上面的加起来可能会爆 r ,于是就没有办法了。。。 后来一看别人博客,他刚提到记录根节点到这个节点的距离和,这才恍然大悟,路径是唯一的呀,马上敲完,1A了。。。  唉,总是差一点,差一点。。。 = =

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int INF = 0x0fffffff;const int MAXN = 500055;int n,l,r;struct Edge{    int t,next,val;}edge[MAXN];int tot,head[MAXN];void add_edge(int s,int t,int val){    edge[tot].t = t;    edge[tot].val = val;    edge[tot].next = head[s];    head[s] = tot++;}int dis;int check(int x){    if( x <= r && x >= l) return 1;    else return 0;}int d[MAXN][2];void dfs(int u){    d[u][0] = d[u][1] = 0;    for(int e = head[u];e != -1;e = edge[e].next)    {        int v = edge[e].t;        int val = edge[e].val;        dis += val;        dfs(v);        dis -= val;        int tmp = dis + val + d[v][1];        //printf("tmp1 = %d\n",tmp);        if(check(tmp))            d[u][0] = min(val + d[v][1],(d[u][0] == 0 ? INF:d[u][0]));        tmp = dis + val + d[v][0];        //printf("tmp2 = %d\n",tmp);        if(check(tmp))            d[u][1] = max(val + d[v][0],d[u][1]);    }    //printf("u = %d,d0 = %d,d1 = %d\n",u,d[u][0],d[u][1]);}int main(){    while(~scanf("%d%d%d",&n,&l,&r))    {        tot=0;        memset(head,-1,sizeof(head));        for(int i = 1;i<n;i++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            add_edge(a,b,c);        }        dis = 0;        dfs(0);        if(d[0][1] == 0) puts("Oh, my god!");        else printf("%d\n",d[0][1]);    }    return 0;}


原创粉丝点击