欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

1463. Happiness to People!

发布时间:2024/6/14 50 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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;elsecontinue;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; }

 

转载于:https://www.cnblogs.com/liulangye/archive/2012/10/29/2744299.html

与50位技术专家面对面20年技术见证,附赠技术全景图

总结

以上是生活随笔为你收集整理的1463. Happiness to People!的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。