poj 3847 树(链接表与堆栈的实现)
来源:互联网 发布:unity3d 上海 外包 编辑:程序博客网 时间:2024/06/03 17:12
Moving to Nuremberg
http://poj.org/problem?id=3847
树中给定各边长及每点要到达的次数。求最优的点,满足所走路径和最小,要求:使得从该点开始访问其他点的次数符合给定要求并且每次只能访问一个点并返回。
思路:
任何一条边可以把树分成两颗子树,假定我们知道了一颗子树需要访问的次数和accessnum,则另一颗访问和是剩下的部分。于是该边上两点啊a,b若选为目标点的花费cost(x)存在关系:cost(b)-cost(a)=accessnum(a)*weight-accessnum(b)*weight[即:选b和选a的差别在于a树的点要过该边而b树的点不用过]。
于是我们可以从叶子节点开始扩展子树,有边<a,b>则,accessnum(b)+=accessnum(a),同时可以求出从b点访问a的子树木的代价cost'(b)+=cost'(a)+accessnum(a)*weight(a,b),直到扩展完整棵树木,此时的cost'(x)就是根的代价cost,其他的都不是。然后根据上一段地公式回溯求出叶子节点的cost(x)。
数据结构:这个题目的时间限制很严格,开始用递归调用严重超时。另外递归调用vc编译只能处理深度超过1万多的,然后就终止。后改用系统的vector存储边/queue或stack跟踪再次超时了。因而需要我们用链接表来存储边,并且实现数组堆栈,以能在规定时间内运行完。此外,数据大要用64位,真是麻烦~
struct Edge{
int b,t;
Edge *next;
}*edge[NUM];
//扩展树,先找叶子节点,cost(a)=cost(b)+lost(a)
memset(flag,true,sizeof(flag)); //标记是否被扩展或者回溯
memset(cost,0,sizeof(cost));
qn = 0;
for(i = 1;i <= n;i ++)
{
if(size[i] == 1)
que[qn++] = i;
}
int x = -1;
while(qn > 0)
{
x = que[--qn];
if(size[x] == 0)break;
Edge *next = edge[x];
for(;next;next = next->next)
{
if(flag[next->b])break;
}
cost[next->b] += tag[x]*next->t+cost[x];
tag[next->b] += tag[x];
lost[x] = (total - 2*tag[x])*next->t;
flag[x] = false;
p[x] = next->b;
size[next->b] --; //扩展完后非叶子又要变成叶子
if(size[next->b] == 1)
que[qn++]=next->b;
}
//回溯
if(x > 0){
que[0] = x;
qn = 1;
}
while(qn > 0)
{
x = que[--qn];
flag[x] = true;
Edge *next = edge[x];
for(;next;next = next->next)
{
if(flag[next->b]||p[next->b] != x)continue;
cost[next->b] = cost[x] + lost[next->b];
que[qn++]=next->b;
}
}
//选择输出最优结果
__int64 res = cost[1];
int ls = 0;
sov[ls++] = 1;
for(i = 2;i <= n;i ++){
if(cost[i] < res)
{
res = cost[i];
ls = 1;
sov[0] = i;
}
else if(cost[i] == res)
sov[ls++] = i;
}
printf("%I64d\n%d",res*2,sov[0]);
for(i = 1;i < ls;i ++)
printf(" %d",sov[i]);
printf("\n");
- poj 3847 树(链接表与堆栈的实现)
- 考研数据结构与算法之堆栈的使用(四)链表实现的堆栈
- (五)链式堆栈的实现与应用
- 【整理】堆栈的特征与实现
- 堆栈的链表实现
- 链接堆栈的基本算法
- 链接堆栈的基本算法
- 考研数据结构与算法之堆栈的使用(三)数组实现的堆栈
- 堆栈的顺序存储结构实现1——堆栈的创建与销毁
- 堆栈与链表与队列代码实现
- JavaScript的数组实现队列与堆栈的方法
- JavaScript的数组实现队列与堆栈的方法
- 4.3 堆栈的链表实现
- 线性表、堆栈、队列的实现总结
- 基于链表的堆栈实现
- 顺序表堆栈的操作实现源码
- ADT堆栈的链表实现
- 堆栈的C实现
- POJ 3821 Clickomania
- POJ 3842 排列问题
- C#爬取动态网页
- poj 3899 The Lucky Numbers
- poj解题报告整理
- poj 3847 树(链接表与堆栈的实现)
- poj 3865 数据库冗余问题判断
- 利用Stanford Parser进行中文行为抽取
- C++及Java连接MySQL方法
- HIT LTP的使用及利用句法关系简单抽取示例
- Java中Object的使用:重载equals、hashCode及实现compareTo
- 文件流fstream处理多个文件
- 带负号大数加减法简单程序
- Word问题集锦