最小直径生成树

#include<bits/stdc++.h>
const int maxn=205,maxm=50010;
using namespace std;	int ans=(int)1e9;
int n,m,d[maxn][maxn],inf,tot,rank[maxn][maxn];
struct Edge{int x,y,v;}E[maxm];
void floyd(){ //强行求出任意两点间最短距离
    for (int k=1;k<=n;k++)
        for (int i=1;i<=n;i++) if (i!=k)
            for (int j=1;j<=n;j++) if (i!=j&&k!=j)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
void work(int id){
    int u=E[id].x,v=E[id].y,L=E[id].v;
    for (int a=1,b=2;b<=n;b++){
        if (d[v][rank[u][a]]>d[v][rank[u][b]]) continue;
ans=min(ans,d[v][rank[u][a]]+d[u][rank[u][b]]+L);
        a=b;
    }
}
int main(){
scanf("%d%d",&n,&m);
memset(d,63,sizeof(d)),inf=d[0][0];
    for (int i=1;i<=n;i++) d[i][i]=0;
for (int i=1,x,y,z;i<=m;i++) {
scanf("%d%d%d",&x,&y,&z);
d[x][y]=d[y][x]=min(d[x][y],z);
}
for (int i=1;i<=n;i++) 
for (int j=1;j<i;j++)
if(d[i][j]!=inf)
E[++tot]=(Edge){j,i,d[i][j]};
    floyd();
for (int i=1;i<=n;i++) 
for (int j=1;j<=n;j++) 
rank[i][j]=j;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            for (int k=j+1;k<=n;k++)
                if (d[i][rank[i][j]]<d[i][rank[i][k]]) 
swap(rank[i][j],rank[i][k]);
for (int i=1;i<=n;i++) 
ans=min(ans,d[i][rank[i][1]]+d[i][rank[i][2]]);
for (int i=1;i<=tot;i++) work(i);
printf("%d\n",ans);}

最小直径生成树

题目:bzoj2180

图的绝对中心就是这样一个点。它可以存在于任何一条边上,并且这个点到所有点的最短距离的最大值最小。

绝对中心到所有点的最短距离的最大值肯定会有两个,而且这两个最短距离位于某条边的两端,也就是说加入绝对中心在u v这条边上,那么肯定存在两个距离相等且最大的最短路径,一条从绝对中心往u方向走,另一条从绝对中心往v方向走

然后我们枚举每一条边,假设绝对中心在这条边上,中心到某个点的最短距离可以表示为min(d[u][s] + x , d[v][s] + L - x) 。设点S在V端,就取右值,S在U端就取左值(X就是从U往V走的距离)

注意画出函数图像来的话就是一条折线。在这条折线上取一个最小值就是中心到s的最短距离的最小值,那到每个点都是这样一条折线,由于要取最短距离的最大值,所以我们的点得在所有折线构成的最上方的折线上取一个最低点

注意以上折线图是一条边到所有点的情况,现需要求全部边对应自身折线图的最低点里的最大值。

将d[u][w]排序,扫描一遍就能求出所有的交点,问题完美解决。

Input         ouput

8 11                   13

1 3 1

1 2 2

2 4 3

2 6 7

4 6 0

6 8 4

8 7 3

7 5 1

6 3 5

7 3 5

5 3 6

 

每边曲线代表一 条边,值是MAX(到U点端最远点距离+X,到V点端最远点距离+L-X)

横坐标是边中长度占比,由U端走到V端的距离,0到W(U,V)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值