HDU

来源:互联网 发布:360极速浏览器mac版 编辑:程序博客网 时间:2024/06/15 12:43

HDU - 3672 


题意:给一棵带权树,初始位置在根节点,最多有1000次询问,问你在x(x<5E6)范围内最大能探索多少个点。

分析:树上的背包问题,对背包问题理解还是不够深刻啊,自己写的时候模型是正确的,动归方程没写出啦,然后参考一下博客。

如果探索完所有点并回到根节点,则所用时间为探索过的所有节点之间的权值的两倍(来回两次)。如果不回到根节点,则减掉所有探索点到当前根节点的最长路径。

因为查询次数较多,范围较大,所以我们记录探索完i个点所需最小x。

所以对于一个节点x 设dp[x][i][0]为探索完i个节点(包括自己,下同)后返回x,dp[x][i][1]表示探索i个点不返回自己的最小路程。

dp[x][i][0]由根节点的dp[y][j][0]通过背包很容易得到。dp[x][i][1]则是选择一个儿子节点的dp[y][j][1]和其他儿子节点得到最小值


ACcode

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int INF=0x3f3f3f3f;int dp[505][505][2],num[505],fa[505],n,m,b[505];struct edge{    int to,cos;    edge(int x,int y)    {        to=x;        cos=y;    }};vector<edge> g[505];void dfs(int x){    if(g[x].size()==0)    {        dp[x][1][0]=dp[x][1][1]=0;        num[x]=1;        return ;    }    num[x]=1;    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i].to;        dfs(y);        num[x]+=num[y];    }    dp[x][1][0]=0;    dp[x][1][1]=0;    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i].to,cost=g[x][i].cos;        for(int v=num[x];v>1;v--)        {            for(int j=1;j<v;j++)            {            dp[x][v][0]=min(dp[x][v][0],dp[x][v-j][0]+dp[y][j][0]+2*cost);            dp[x][v][1]=min(dp[x][v][1],min(dp[x][v-j][0]+dp[y][j][1]+cost,                                dp[x][v-j][1]+dp[y][j][0]+2*cost));            }        }    }}void init(){    memset(dp,0x3f,sizeof(dp));    memset(fa,-1,sizeof(fa));    for(int i=0;i<n;i++)        g[i].clear();}int main(){    int x,y,z,cas=1;    while(scanf("%d",&n)!=EOF&&(n))    {        init();        for(int i=1;i<n;i++)        {            scanf("%d%d%d",&x,&y,&z);            g[y].push_back(edge(x,z));            fa[x]=y;        }        for(int i=0;i<n;i++)        {            if(fa[i]==-1)            {                dfs(i);                for(int v=num[i];v>=0;v--)                {                    b[v]=dp[i][v][1];                }                break;            }        }        //for(int i=0;i<=n;i++)cout<<b[i]<<" ";cout<<endl;        b[n+1]=INF;        scanf("%d",&x);        printf("Case %d:\n",cas++);        while(x--)        {            scanf("%d",&y);            for(int i=1;i<=n+1;i++)            {                if(y<b[i])                {                    printf("%d\n",i-1);                 break;                }            }        }    }    return 0;}


原创粉丝点击