【noip2007】树网的核

来源:互联网 发布:深圳水务集团网络投诉 编辑:程序博客网 时间:2024/05/14 07:33

题目描述

设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;}
原创粉丝点击