• 1463. Happiness to People! 夜


    http://acm.timus.ru/problem.aspx?space=1&num=1463

    树形DP  

    此题有个陷阱   就是图的本身是一个森林 不是树

    由于所有 happiness 的值都为非负 所有最优路径一定是从一个叶子节点到另一个叶子节点(当然 两个节点可能一样)

    思路:

    包含一个节点 和 两个节点的 树特殊处理

    对应3个节点以及3个节点以上的树 一定能找到一个初度 大于等于2 的点 以此点为根节点更新

    对于这个树  dfs  记录每个点向下的第一最优路径选择 和第二最优路径选择

    然后不断向上更新

    最后 把所有向下路径至少两条的节点 将此类节点的两个最优路径 连起来的路径进行和最终答案比较 择优而选

    刚开始用 vector 建图 结果超内存了 看来 vector 的时间和空间占用都比较大

    代码及其注释:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<vector>
    #include<set>
    #include<map>
    #include<string>
    #include <iomanip>
    using namespace std;
    const int N=50005;
    int head[N],I;
    struct node
    {
        int j,h,next;
    }side[N*2];//双向边
    int out[N],sub[N],next1[N],next2[N];//初度 ,子树最优长度 ,第一选择路径,第二选择路径
    vector<int>ans;
    int a[N];
    void Add(int i,int j,int h)
    {
        side[I].j=j;
        side[I].h=h;
        side[I].next=head[i];
        head[i]=I++;
    }
    int Optimal(int i)//以此点为根节点的树中 最优路径长度
    {
        if(out[i]==0)
        return a[i];
        if(out[i]==1)
        return a[i]+a[side[head[i]].j]+side[head[i]].h;
        return a[i]+side[next1[i]].h+sub[side[next1[i]].j]+side[next2[i]].h+sub[side[next2[i]].j];
    }
    int Fhappy(int x,int i)//从x节点选择i路径向下的路径长度
    {
        return (side[i].h+sub[side[i].j]);
    }
    int dfs(int x,int pre)
    {
        for(int t=head[x];t!=-1;t=side[t].next)
        {
            int l=side[t].j;
            if(l==pre)
            continue;
            dfs(l,x);
            if(next2[x]==-1||Fhappy(x,t)>Fhappy(x,next2[x]))//更新最优选择路径
            next2[x]=t;
            else
            continue;
            if(next1[x]==-1||Fhappy(x,next2[x])>Fhappy(x,next1[x]))//更新最优选择路径
            swap(next2[x],next1[x]);
        }
        sub[x]=a[x];
        if(next1[x]!=-1)
        sub[x]+=Fhappy(x,next1[x]);
        return sub[x];
    }
    int main()
    {
        //freopen("data.txt","r",stdin);
        int n,m;
        while(scanf("%d %d",&n,&m)!=EOF)
        {
           memset(head,-1,sizeof(head));I=0;
           memset(next1,-1,sizeof(next1));
           memset(next2,-1,sizeof(next2));
           memset(out,0,sizeof(out));
           for(int i=1;i<=n;++i)
           scanf("%d",&a[i]);
           int l,r,h;
           while(m--)
           {
               scanf("%d %d %d",&l,&r,&h);
               Add(l,r,h);
               Add(r,l,h);
               ++out[l];
               ++out[r];
           }
           int k=-1;
           for(int i=1;i<=n;++i)
           {
               if(out[i]>=2&&next1[i]==-1)
               {
                   dfs(i,-1);
                   if(k==-1||Optimal(i)>Optimal(k))
                   k=i;
               }
           }
           for(int i=1;i<=n;++i)
           {
               if(out[i]>=3)
               {
                   if(k==-1||Optimal(i)>Optimal(k))
                   k=i;
               }else if(out[i]==0)//只有一个点才情况
               {
                   if(k==-1||Optimal(i)>Optimal(k))
                   k=i;
               }else if(out[i]==1&&out[side[head[i]].j]==1)//只有两个点的情况
               {
                   if(k==-1||Optimal(i)>Optimal(k))
                   k=i;
               }
           }
           if(out[k]<=1)
           {
               printf("%d\n",Optimal(k));
               if(out[k]==0)
               {printf("1\n");printf("%d\n",k);}
               else
               {printf("2\n");printf("%d %d\n",k,side[head[k]].j);}
               continue;
           }
           ans.clear();
           ans.push_back(k);//将最优路径存到 ans 里面
           int tmp=side[next1[k]].j;
           do{
             ans.push_back(tmp);
             if(next1[tmp]==-1)
             break;
             tmp=side[next1[tmp]].j;
           }while(true);
           tmp=side[next2[k]].j;
           do{
             ans.insert(ans.begin(),tmp);
             if(next1[tmp]==-1)
             break;
             tmp=side[next1[tmp]].j;
           }while(true);
           printf("%d\n",Optimal(k));
           printf("%d\n",ans.size());
           for(unsigned int i=0;i<ans.size();++i)
           printf("%d ",ans[i]);
           printf("\n");
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    yum安装LAMP
    CentOS7添加永久静态路由
    批量解压缩,显示进度条(2)
    Django静态文件配置
    大家同乐一下,搞了三天的字符串与STL!终于搞好了。。
    C++动态分配空间
    UNICODE问题
    VC编码规范 (转)
    vs2008中添加splash screen[分享]
    E
  • 原文地址:https://www.cnblogs.com/liulangye/p/2744299.html
Copyright © 2020-2023  润新知