hihoCoder 1035 自驾旅行 树形DP

来源:互联网 发布:淘宝女装级别最高 编辑:程序博客网 时间:2024/04/29 09:52

题目链接:http://hihocoder.com/problemset/problem/1035

题目显然是一个树形DP,我们用dp[ i ][ j ]表示已经询问了子树i的所有关键节点,人车的一个状态。其中

j==0:人去,不管人是否回来

j==1:人去,人一定要回来

j==2:人车都去,人车都要回来

j==3:人车都去,人一定要回来,车不管

j==4:人车都去,不管人车最后是否回来。

注意,这里显然有 dp[i][1]>=dp[i][0]  ,dp[i][1]>=dp[i][2]>=dp[i][3]>=dp[i][4]

我们先考虑比较容易计算的,我们记人走边(fa,son)的花费为w1(fa,son),车为w2(fa,son),显然

  • dp[fa][1] = ∑ dp[son][1] + 2*w1(fa,son)
  • dp[fa][2] = ∑ min( dp[son][1] +2* w1(fa,son) , dp[son][2] + 2*w2(fa,son) )
现在我们考虑复杂一点的情况,dp[fa][0]和dp[fa][3]

对dp[fa][0],其实就是有一个边选择为 dp[son][0] + w1(fa,son) 而其他的都选择 dp[son][1] + 2*w1(fa,son);或者都选后者,我们记

  • temp = min(dp[son][0] - dp[son][1] - w1(fa,son) ),temp = min(temp,0)
  • 则 dp[fa][0] = dp[fa][1] + temp;
现在解决dp[fa][3],为了解释的方便,我们记 t2 = min( dp[son][1] +2* w1(fa,son) , dp[son][2] + 2*w2(fa,son) )

dp[fa][3]的决策方式,其实就是一个选择 w2(fa,son) + dp[son][3] + w1(fa,son) ,其他的选t2,或者都选t2,这样我们得到dp[fa][3]的转移方程

  • t3=0,t3=min( t3 , w1(fa,son)+ w2(fa,son)+ dp[son][3] - t2 );
  • dp[fa][3] = dp[fa][2] + t3;
dp[fa][4]则是一个比较复杂的过程,我们从走的最后一棵子树考虑

1、走最后一棵子树时,还有车

这样的情况还是很好计算的,最后一棵子树的选择是 min( w1(fa,son) + dp[son][0] , w2(fa,son) + dp[son][4] ) 而其他选择都是t2。或者全部选择t2。

2、走最后一棵子树时,没有车了。

这种情况大概就是,最后一棵子树的决策是w1(fa,son)+w2(fa,son)+dp[son][3];其他的,某一棵子树,人车走下去,然后只有人回来了,剩下的决策是t2。

这个情况是最麻烦的,因为有两棵特殊的子树,我们类似上面的差值统计的时候,要避免两个差值代表同一个子树。为了解决这个问题,我最开始的方法是,先后将两个差值的优先级设为不同,这样统计的话,可以避免重复子树。但是因为顺序处理没处理好,我的代码最开始有BUG。但是因为能A这题,所以我没注意到。

这里多谢swwlqw的指点,这个问题现在已经改正。

我们记

  • ff1 = w1(fa,son)+ w2(fa,son)+ dp[son][3] - t2;
  • ff2 = w1(fa,son)+ dp[son][0] - t2;
我们的目标是找到不同son,使得ff1 + ff2 最小。我们可以先去找ff1的最小和次小,并记录达到最小ff1的儿子match。再遍历一下所有儿子,如果此时的son就是match,那么就配合ff1的次小值,否则配合最小值。

//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<cmath>#include<cctype>#include<string>#include<algorithm>#include<iostream>#include<ctime>#include<map>#include<set>using namespace std;#define MP(x,y) make_pair((x),(y))#define PB(x) push_back(x)typedef long long LL;//typedef unsigned __int64 ULL;/* ****************** */const int INF=100011122;const double INFF=1e100;const double eps=1e-8;const int mod=1000000007;const int NN=1000010;const int MM=1000010;/* ****************** */struct G{    int v,w1,w2,next;}E[NN*2];int p[NN],T;bool vis[NN];LL dp[NN][5];int si[NN];void add(int u,int v,int w1,int w2){    E[T].v=v;    E[T].w1=w1;    E[T].w2=w2;    E[T].next=p[u];    p[u]=T++;}void dfs(int u,int fa){    int i,v;    si[u]=vis[u];    LL temp=0,t2,t3=0,t41=0;    LL f1,f2,ff1,ff2;    int match = -1;    f1=f2=1LL<<50;    dp[u][1]=0;    dp[u][2]=0;    dp[u][4]=0;    for(i=p[u];i+1;i=E[i].next)    {        v=E[i].v;        if(v==fa)continue;        dfs(v,u);        si[u]+=si[v];        if(si[v]>0)        {            temp=min(temp,dp[v][0]-dp[v][1]-E[i].w1);            dp[u][1]+=dp[v][1]+E[i].w1*2;            t2=min(dp[v][1]+E[i].w1*2,dp[v][2]+E[i].w2*2);            dp[u][2]+=t2;            t3=min(t3,E[i].w1+E[i].w2+dp[v][3]-t2);            dp[u][4]+=t2;            t41=min(t41, min(dp[v][0]+E[i].w1,dp[v][4]+E[i].w2) - t2 );            ff1=E[i].w1+E[i].w2+dp[v][3]-t2;            if(ff1<f1)            {                match = v;                f2 = f1;                f1 = ff1;            }            else                f2=min(f2,ff1);        }    }    dp[u][0]=dp[u][1]+temp;    dp[u][3]=dp[u][2]+t3;    dp[u][4]+=t41;    dp[u][4]=min(dp[u][4],dp[u][3]);    for(i=p[u];i+1;i=E[i].next)    {        v=E[i].v;        if(v==fa)continue;        if(si[v]>0)        {            t2=min(dp[v][1]+E[i].w1*2,dp[v][2]+E[i].w2*2);            ff2=E[i].w1+dp[v][0]-t2;            if(v==match)                dp[u][4] = min(dp[u][4], dp[u][2] + f2 + ff2);            else                dp[u][4] = min(dp[u][4], dp[u][2] + f1 + ff2);        }    }}int main(){    int n,m,i,u,v,w1,w2;    while(scanf("%d",&n)!=EOF)    {        memset(p,-1,sizeof(p));        T=0;        memset(vis,false,sizeof(vis));        for(i=1;i<n;i++)        {            scanf("%d%d%d%d",&u,&v,&w1,&w2);            add(u,v,w1,w2);            add(v,u,w1,w2);        }        scanf("%d",&m);        for(i=1;i<=m;i++)        {            scanf("%d",&u);            vis[u]=true;        }        dfs(1,-1);        cout<<min(dp[1][0],dp[1][4])<<endl;    }    return 0;}



0 0
原创粉丝点击