题目描述
设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点。
路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和。我们称d(a, b)为a, b两结点间的距离。
D(v, P)=min{d(v, u), u为路径P上的结点}。
树网的直径:树网中最长的路径成为树网的直径。对于给定的树网T,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
偏心距ECC(F):树网T中距路径F最远的结点到路径F的距离,即
ECC(F)=max{d(v, F),v∈V}
任务:对于给定的树网T=(V, E, W)和非负整数s,求一个路径F,他是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过s(可以等于s),使偏心距ECC(F)最小。我们称这个路径为树网T=(V, E, W)的核(Core)。必要时,F可以退化为某个结点。一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。
下面的图给出了树网的一个实例。图中,A-B与A-C是两条直径,长度均为20。点W是树网的中心,EF边的长度为5。如果指定s=11,则树网的核为路径DEFG(也可以取为路径DEF),偏心距为8。如果指定s=0(或s=1、s=2),则树网的核为结点F,偏心距为12。
输入输出格式
输入格式:
输入文件core.in包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为树网结点的个数,s为树网的核的长度的上界。设结点编号以此为1,2,……,n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
输出格式:
输出文件core.out只有一个非负整数,为指定意义下的最小偏心距。
输入输出样例
输入样例#1: 复制
5 2
1 2 5
2 3 2
2 4 4
2 5 3
输出样例#1: 复制
5
输入样例#2: 复制
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
输出样例#2: 复制
5
说明
40%的数据满足:5<=n<=15
70%的数据满足:5<=n<=80
100%的数据满足:5<=n<=300,0<=s<=1000。边长度为不超过1000的正整数
NOIP 2007 提高第四题
终于能够独立AC T4 了,3.5h惊天大模拟;
本蒟蒻看不出算法,只好模拟+暴力+最短路;
没想到竟然过了
简要说下思路:
一:跑个Floyed求出两点之间的距离(好像有点浪费,但数据范围这么小,就瞎写吧。。)
二:跑bfs求出图中最长的路径(即题中的直径),实现方法上:建一个结构体Node 存储点的 id(编号),dis(距离起点的距离),step(到达这个点时走的步数),pre(这个点的前驱),然后一起扔到队列里。与当前最优值更新存到road里即可;
在这里我是选取出度为1的点广搜的,小贪心,很容易理解吧
三:接下来就是暴力的不能再暴力了
枚举直径上所有的合法的路径,对于每一条路径枚举所有的点到这条路径的最小值,在这些里面选一个最大值(最远距离)。最后取所有的路径中的最小值(最小的最大偏心距)。输出即可。
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,s,chu[301];
struct Edge{
int to,next,dis;
}edge[1001];
bool b[301];
struct Node{
int id,dis,step,pre;
}node[301];
queue<Node> que;
int maxstep; int nowmax=0;//nowmax不能放在spfa里面啊
int f[301][301];
int ans=0x7fffffff;
int head[301],num_edge;
void add_edge(int from,int to,int dis)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
edge[num_edge].dis=dis;
head[from]=num_edge;
}
int maxdis; int road[301],tot;
void dfs(int x,int step,int dis)//这是用深搜写的求直径的方法,但是不知道为什么WA了几个点,大佬们帮我看看也好
{
if (step==1) road[1]=x;
if (dis>maxdis)
{
maxdis=dis; road[step]=x; maxstep=step;
}
b[x]=true;
for (int i=head[x]; i!=0; i=edge[i].next)
{
if (!b[edge[i].to])
{
dfs(edge[i].to,step+1,dis+edge[i].dis);
}
}
}
void spfa(int x)
{
memset(b,0,sizeof(b));//不要忘记每次清零
memset(node,0,sizeof(node));
b[x]=true;//起点标记
for (int i=1; i<=n; i++) node[i].id=i;
node[x].dis=0; node[x].step=1;
que.push(node[x]);
while (!que.empty())
{
Node now=que.front(); que.pop();
int t=0;
for (int i=head[now.id]; i!=0; i=edge[i].next)
{
if (!b[edge[i].to])
{
t++;
b[edge[i].to]=true;
node[edge[i].to].dis=now.dis+edge[i].dis;
node[edge[i].to].pre=now.id;
node[edge[i].to].step=now.step+1;
que.push(node[edge[i].to]);
}
}
// if (nowmax<now.dis&&!t)//从终点(没有出度)向前保存路径
if (nowmax<now.dis&&chu[now.id]==1&&now.id!=x)
{
nowmax=now.dis;
maxstep=now.step;
road[now.step]=now.id;
int p=now.pre;
while (p)
{
road[node[p].step]=node[p].id; p=node[p].pre;
}
}
}
}
void Floyed()
{
for (int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
// if (i!=j&&j!=k&&i!=k)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
/* for (int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++) printf("%d ",f[i][j]);
printf("\n");
}*/
}
bool vis[301],used[301]; int max_dis;
void work(int x,int y)
{
int road_max=0;
for (int i=1; i<=n; i++)
{
int node_min=0x7fffffff;
for (int j=x; j<=y; j++)
{
// if (i!=road[j])
node_min=min(node_min,f[i][road[j]]);
}
road_max=max(road_max,node_min);
}
ans=min(ans,road_max);
}
int main()
{
scanf("%d%d",&n,&s);
memset(f,0x7f/3,sizeof(f));
for (int i=1; i<=n; i++) f[i][i]=0;
for (int i=1; i<=n-1; i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add_edge(x,y,z); add_edge(y,x,z);
f[x][y]=f[y][x]=z;
chu[x]++; chu[y]++;
}
Floyed();
for (int i=1; i<=n; i++)
if (chu[i]==1)
{
// dfs(i,1,0);
spfa(i);
}
/* int maxn=0; int k;
for (int i=head[road[2]]; i!=0; i=edge[i].next)
if (maxn<edge[i].dis) {maxn=edge[i].dis; k=edge[i].to;}
road[1]=k;
for (int i=1; i<=maxstep; i++) printf("%d ",road[i]);*/
for (int i=1; i<=maxstep; i++)
{
for (int j=i; j<=maxstep; j++)
{
if (f[road[i]][road[j]]>s) break;
work(i,j);
}
}
printf("%d",ans);
return 0;
}