hdu 3721 树的最小直径
题意:
给你一棵树,让你改变一条边,改变之后依然是一棵树,然后问你怎样改变才能让树的直径最短。这里的改变一条边指的是指把一条边长度不变,连在别的两个点上。
思路:
首先求出树的直径,把直径上的边记录下来,然后在枚举这些边(枚举别的边没意义)每次枚举我的做法是后建造两棵树,我们只要在这两棵树之间连接一条边就行了,但是怎么连接呢? 我是先没别求两棵树的直径,然后在找到直径上中间点,然后连接这两棵树的中间点,只有这样才能保证最短,每次连接后的直径就是 两棵树的直径,和当前枚举的边长度+两个树被中间点分开的较长的那一个值的和,他们三个中较长的哪一个,就这样在所有中找到一个最小的就是答案。
#include<stdio.h>
#include<string.h>
#include<queue>
#include<map> #define N_node 2500 + 5
#define N_edge 5000 + 5
#define INF 1000000000
using namespace std; typedef struct
{
int to ,next ,cost;
}STAR; typedef struct
{
int a ,b ,c;
}EDGE; STAR E[N_edge];
EDGE edge[N_node];
int list[N_node] ,tot;
int s_x[N_node] ,mer[N_node];
map<int ,map<int ,int> >hash; void add(int a ,int b ,int c)
{
E[++tot].to = b;
E[tot].cost = c;
E[tot].next = list[a];
list[a] = tot; E[++tot].to = a;
E[tot].cost = c;
E[tot].next = list[b];
list[b] = tot;
} void Spfa(int s ,int n)
{
for(int i = 0 ;i <= n ;i ++)
s_x[i] = INF ,mer[i] = i;
int mark[N_node] = {0};
s_x[s] = 0 ,mark[s] = 1;
queue<int>q;
q.push(s);
while(!q.empty())
{
int xin ,tou;
tou = q.front();
q.pop();
mark[tou] = 0;
for(int k = list[tou] ;k ;k = E[k].next)
{
xin = E[k].to;
if(s_x[xin] > s_x[tou] + E[k].cost)
{
s_x[xin] = s_x[tou] + E[k].cost;
mer[xin] = tou;
if(!mark[xin])
{
mark[xin] = 1;
q.push(xin);
}
}
}
}
return ;
} int abss(int x)
{
return x > 0 ? x : -x;
} int maxx(int x ,int y)
{
return x > y ? x : y;
} int main ()
{
int t ,n ,a ,b ,c ,i ,j;
int cas = 1;
scanf("%d" ,&t);
while(t--)
{
scanf("%d" ,&n);
memset(list ,0 ,sizeof(list));
tot = 1;
for(i = 1 ;i < n ;i ++)
{
scanf("%d %d %d" ,&edge[i].a ,&edge[i].b ,&edge[i].c);
edge[i].a ++ ,edge[i].b ++;
add(edge[i].a ,edge[i].b ,edge[i].c);
} int p01 ,p02;
Spfa(1 ,n);
int maxxx = -1;
for(j = 1 ;j <= n ;j ++)
if(maxxx < s_x[j] && s_x[j] != INF)
{
maxxx = s_x[j];
p01 = j;
}
Spfa(p01 ,n);
maxxx = -1;
for(j = 1 ;j <= n ;j ++)
if(maxxx < s_x[j] && s_x[j] != INF)
{
maxxx = s_x[j];
p02 = j;
}
int x = p02;
hash.clear();
while(x != mer[x])
{
hash[x][mer[x]] = hash[mer[x]][x] = 1;
x = mer[x];
} int ans = INF;
for(i = 1 ;i < n ;i ++)
{
if(!hash[edge[i].a][edge[i].b]) continue;
memset(list ,0 ,sizeof(list)) ,tot = 1;
for(j = 1 ;j < n ;j ++)
if(j == i) continue;
else add(edge[j].a ,edge[j].b ,edge[j].c); int p11 ,p12 ,mid1 ,l1 ,mid1l;
Spfa(edge[i].a ,n);
int max = -1;
for(j = 1 ;j <= n ;j ++)
if(max < s_x[j] && s_x[j] != INF)
{
max = s_x[j];
p11 = j;
}
Spfa(p11 ,n);
max = -1;
for(j = 1 ;j <= n ;j ++)
if(max < s_x[j] && s_x[j] != INF)
{
max = s_x[j];
p12 = j;
}
l1 = max;
int x = p12;
int min = INF;
while(x != mer[x])
{
if(min > abss(s_x[x] - (l1 - s_x[x])))
{
min = abss(s_x[x] - (l1 - s_x[x]));
mid1 = x;
mid1l = maxx(s_x[x] ,l1 - s_x[x]);
}
x = mer[x];
}
if(min > abss(s_x[x] - (l1 - s_x[x])))
{
min = abss(s_x[x] - (l1 - s_x[x]));
mid1 = x;
mid1l = maxx(s_x[x] ,l1 - s_x[x]);
} int p21 ,p22 ,mid2 ,l2 ,mid2l;
Spfa(edge[i].b ,n);
max = -1;
for(j = 1 ;j <= n ;j ++)
if(max < s_x[j] && s_x[j] != INF)
{
max = s_x[j];
p21 = j;
}
Spfa(p21 ,n);
max = -1;
for(j = 1 ;j <= n ;j ++)
if(max < s_x[j] && s_x[j] != INF)
{
max = s_x[j];
p22 = j;
}
l2 = max;
x = p22;
min = INF;
while(x != mer[x])
{
if(min > abss(s_x[x] - (l2 - s_x[x])))
{
min = abss(s_x[x] - (l2 - s_x[x]));
mid2 = x;
mid2l = maxx(s_x[x] ,l2 - s_x[x]);
}
x = mer[x];
}
if(min > abss(s_x[x] - (l2 - s_x[x])))
{
min = abss(s_x[x] - (l2 - s_x[x]));
mid2 = x;
mid2l = maxx(s_x[x] ,l2 - s_x[x]);
} int now = maxx(maxx(l1 ,l2) ,edge[i].c + mid1l + mid2l);
if(ans > now) ans = now;
}
printf("Case %d: %d\n" ,cas ++ ,ans);
}
return 0;
}
hdu 3721 树的最小直径的更多相关文章
- hdu 3721 树的直径
思路:枚举+树的直径 #include<iostream> #include<cstring> #include<cstdio> #include<algor ...
- HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)
HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由 ...
- HDU 1954 Subway tree systems (树的最小表示法)
题意:用一个字符串表示树,0代表向下走,1代表往回走,求两棵树是否同构. 分析:同构的树经过最小表示会转化成两个相等的串. 方法:递归寻找每一棵子树,将根节点相同的子树的字符串按字典序排列,递归回去即 ...
- HDU 4607 Park Visit 树的最大直径
题意: 莱克尔和她的朋友到公园玩,公园很大也很漂亮.公园包含n个景点通过n-1条边相连.克莱尔太累了,所以不能去参观所有点景点. 经过深思熟虑,她决定只访问其中的k个景点.她拿出地图发现所有景点的入口 ...
- hdu 4612 无向图连通分量缩点,然后求树的最大直径
#pragma comment(linker,"/STACK:102400000,102400000") #include <iostream> #include &l ...
- Warm up HDU - 4612 树的直径
题意:给出n个点和m条边的无向图,存在重边,问加一条边以后,剩下的桥的数量最少为多少. 题解: 你把这个无向图缩点后会得到一个只由桥来连接的图(可以说这个图中的所有边都是桥,相当于一棵树),然后我们只 ...
- bzoj2180: 最小直径生成树
Description 输入一个无向图G=(V,E),W(a,b)表示边(a,b)之间的长度,求一棵生成树T,使得T的直径最小.树的直径即树的最长链,即树上距离最远的两点之间路径长度. Input 输 ...
- hdu 5274 树链剖分
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- 【学习笔记】最小直径生成树(MDST)
简介 无向图中某一点(可以在顶点上或边上),这个点到所有点的最短距离的最大值最小,那么这个点就是 图的绝对中心. 无向图所有生成树中,直径最小的一个,被称为 最小直径生成树. 图的绝对中心的求法 下文 ...
随机推荐
- 如何使用python爬取网页动态数据
我们在使用python爬取网页数据的时候,会遇到页面的数据是通过js脚本动态加载的情况,这时候我们就得模拟接口请求信息,根据接口返回结果来获取我们想要的数据. 以某电影网站为例:我们要获取到电影名称以 ...
- nginx错误分析 `104: Connection reset by peer`
故障描述 应用从虚拟机环境迁移到kubernetes环境中,有些应用不定时出现请求失败的情况,且应用没有记录任何日志,而在NGINX中记录502错误.我们查看了之前虚拟机中的访问情况,没有发现该问题. ...
- ApiTesting全链路接口自动化测试框架 - 新增数据库校验(二)
在这之前我完成了对于接口上的自动化测试:ApiTesting全链路接口自动化测试框架 - 初版(一) 但是对于很多公司而言,数据库的数据校验也尤为重要,另外也有小伙伴给我反馈希望支持. 所以最近几天我 ...
- CF482E ELCA
一.题目 点此看题 二.解法 题目的提示已经足够明显了吧,肯定是要写一个 \(\tt link-cut-tree\) .我们只需要求出总和,再除以方案数就是期望.然后可以算每个点为 \(\tt lca ...
- Everything about WSL 1 you want to know
关于 WSL 1 入门,你应该知道这些 如有错误,欢迎指出 参考: WSL 文档 VMware Workstation Pro 文档 概述 通过 WSL 2 来认识 WSL 1 什么是 WSL 2? ...
- fianl关键词
一.final关键字概述 final关键字具有最终或不可改变的含义,可用于修饰类.变量.方法.因此被final修饰的类.变量.方法具有以下特征: --final修饰的类不能被继承: --final修饰 ...
- ECharts系列 (01):地图三级下钻
前言 最近项目中用到了地图下钻功能,GitHub上找到了一个轮子 - echarts3-chinese-map-drill-down,启动项目看了一下Demo,动画衔接的很流畅,感觉做的非常棒,膜拜大 ...
- 【Azure 服务总线】详解Azure Service Bus SDK中接收消息时设置的maxConcurrentCalls,prefetchCount参数
(Azure Service Bus服务总线的两大类消息处理方式: 队列Queue和主题Topic) 问题描述 使用Service Bus作为企业消息代理,当有大量的数据堆积再Queue或Topic中 ...
- 想了解FlinkX-Oracle Logminer?那就不要错过这篇文章
FlinkX-Oracle Logminer模块是FlinkX基于Logminer对Oracle重做日志进行实时采集分析,可对Oracle进行实时同步也可以通过指定SCN或者时间戳从某个节点进行同步, ...
- Keepalived+Nginx高可用实例
Keepalived+Nginx高可用实例 注意事项: 1.VIP不需要在服务器网络配置文件中配置. 2.nginx主不可用时,需要kill掉nginx主的keepalived服务,这样才可以实现VI ...