Center

来源:互联网 发布:知乎产品分析报告 编辑:程序博客网 时间:2024/04/30 12:01

题目描述

这里写图片描述

简单思路

做一次floyd。
接着枚举一条边,其两个端点为u和v,长度为c。
设终点在这条边上,距离u的距离为x。
那么点i到终点的最短路为min(dis[i][u]+x,dis[i][v]+c-x)
我们把从u节点走到终点的这些节点集合称为A集合,其余称为B集合。
那么一个终点的贡献就是min(A集合中点到u的最短路最大值+x,B集合中点到v的最短路最大值+c-x)
我们可以计算出每个A集合的点在x到达多少后其会成为B集合的点,把这些时刻称为关键时刻,然后离散所有关键时刻。
那么相邻两个关键时刻之间的段A、B集合固定!
想想如何维护A、B集合,A集合只有删除,B集合只有添加,B随便维护,A集合先排序,每次查看最大值是否被删除即可。
接着一个区间内的极点显然是从u或是v走过来都相等的时候,可以解方程算出x,但如果x不在区间内说明极点已过,极值应该在两端。
于是本题就解决了。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef double db;const int maxn=200+10,maxm=50000+10;const db eps=0.001;int dis[maxn][maxn],from[maxm],go[maxm],dist[maxm],id[maxn],wz[maxn];bool bz[maxn];struct dong{    db x;    int id;} a[maxn],b[maxn];int i,j,k,t,n,m,top,tot,u,v,c;db ans,p,q,x,l,r,c1,c2;bool cmp(dong a,dong b){    return a.x<b.x;}int main(){    freopen("center.in","r",stdin);freopen("center.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,n)        fo(j,1,n)            if (i!=j) dis[i][j]=1000000000;    fo(i,1,m){        scanf("%d%d%d",&from[i],&go[i],&dist[i]);        dis[from[i]][go[i]]=dist[i];        dis[go[i]][from[i]]=dist[i];    }    fo(k,1,n)        fo(i,1,n)            if (i!=k)                fo(j,1,n)                    if (j!=k)                        if (i!=j)                            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);    ans=1000000000;    fo(i,1,m){        q=0;        u=from[i];v=go[i];c=dist[i];        a[1].x=a[1].id=a[2].id=0;a[top=2].x=c;        tot=0;        fo(j,1,n){            if (dis[j][u]<dis[j][v]+c){                p=(db)(dis[j][v]+c-dis[j][u])/2;                if (0<p&&p<c){                    a[++top].x=p;                    a[top].id=j;                }                b[++tot].x=dis[j][u];                b[tot].id=j;            }            else if (q<dis[j][v]) q=dis[j][v];        }        sort(a+1,a+top+1,cmp);        sort(b+1,b+tot+1,cmp);        fo(j,1,tot) bz[wz[b[j].id]=j]=0;        fo(j,1,top-1){            if (a[j].id){                bz[wz[a[j].id]]=1;                if (q<dis[a[j].id][v]) q=dis[a[j].id][v];            }            while (tot&&bz[tot]) tot--;            c1=b[tot].x;            c2=q;            x=(c2+c-c1)/2;            if (a[j].x<=x&&x<=a[j+1].x) ans=min(ans,c1+x);            else ans=min(ans,min(max(c1,c2+c),max(c1+c,c2)));        }    }    printf("%.2lf\n",ans);}
0 0
原创粉丝点击