UVA 12223 Moving to Nuremberg (树形dp)

来源:互联网 发布:东方时尚驾校网络授课 编辑:程序博客网 时间:2024/06/12 19:44

题意:

题目给出一颗n个点的树,一个人可以选择任意的位置作为开始点,然后去他喜欢的景点玩,每个景点要玩ni次,每次出去经过每个景点只能算一次,要回去之后再出来才能重新计数。但是每条边都有一个距离,现在问那些点能让他走的距离最短,出处距离和点。

题解:

这题要重根节点往子节点跟新,首先计算出最开始的根节点需要的距离,然后丛上往下跟新将起始点转移到子节点,对于某个父节点u,子节点v,如果把起始节点转移从u转到v,会产生这样的影响:v以下的节点需要走的距离会减少num[v]*w*2,v以上的节点则会增加(sum-nun[v])*w*2,w表示u-v这条边的距离,num[v]表示以v为跟的树景点的次数和,sum是总和。那么转态返程:dp[v]=dp[u]+(sum-num[v])*w*2-num[v]*w*2;

#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>#include<map>#include<set>#define B(x) (1<<(x))using namespace std;typedef long long ll;void cmax(int& a,int b){ if(b>a)a=b; }void cmin(int& a,int b){ if(b<a)a=b; }void cmax(ll& a,ll b){ if(b>a)a=b; }void cmin(ll& a,ll b){ if(b<a)a=b; }void add(int& a,int b,int mod){ a=(a+b)%mod; }void add(ll& a,ll b,ll mod){ a=(a+b)%mod; }const int oo=0x3f3f3f3f;const ll OO=0x3f3f3f3f3f3f3f3f;const int MOD=100007;const int maxn=50005;const int maxm=10000005;struct EDGE{    int v,w,next;}E[maxn<<1];int head[maxn],tol;ll dp[maxn];ll num[maxn],sum;int T,n,m;int u,v,w;void Init(){    memset(head,-1,sizeof head);    tol=0;}void add_edge(int u,int v,int w){    E[tol].v=v;    E[tol].w=w;    E[tol].next=head[u];    head[u]=tol++;}int dfs(int u,int pre,int len){    dp[1]+=len*num[u];    for(int i=head[u];i!=-1;i=E[i].next){        int v=E[i].v;        if(v==pre)continue;        dfs(v,u,len+E[i].w*2);        num[u]+=num[v];    }}void tree_dp(int u,int pre){    for(int i=head[u];i!=-1;i=E[i].next){        int v=E[i].v;        if(v==pre)continue;        dp[v]=dp[u]+(sum-num[v])*E[i].w*2-num[v]*E[i].w*2;        tree_dp(v,u);    }}void input(){    scanf("%d",&n);    for(int i=1;i<n;i++){        scanf("%d %d %d",&u,&v,&w);        add_edge(u,v,w);        add_edge(v,u,w);    }    memset(num,0,sizeof num);    scanf("%d",&m);    sum=0;    for(int i=1;i<=m;i++){        scanf("%d %d",&u,&w);        num[u]=w;        sum+=w;    }    dp[1]=0;}void solve(){    ll ans=OO;    for(int i=1;i<=n;i++)        cmin(ans,dp[i]);    cout<<ans<<endl;    int f=0;    for(int i=1;i<=n;i++){        if(dp[i]==ans){            if(f++) printf(" ");            printf("%d",i);        }    }    puts("");}int main(){    //freopen("E:\\read.txt","r",stdin);    scanf("%d",&T);    while(T--){        Init();        input();        dfs(1,-1,0);        tree_dp(1,-1);        solve();    }    return 0;}




0 0
原创粉丝点击