UVAlive 5869 Airport 解题报告

来源:互联网 发布:淘宝网中华活胰宝 编辑:程序博客网 时间:2024/05/16 08:18

题目

Tri_integral Trainning 4

题意:

一个图,有两种点:旅店和旅客中心。要建一个机场p,对于每个旅店i,用 s(p,i)表示从机场到某个旅客中心再到这个旅店的最短距离。每个旅店有一个旅客人数t(i),要使 s(pi)×t(i)的最大值最小。机场可以建在任意点上或边的某个位置上。

题解:

首先用floyd处理任意一个点作为机场的各 s(pi)。然后枚举每条边二分答案:

对于二分的答案mid,任意 s(pi)×t(i)都不能这个值,但是机场可能先经过枚举的边的u或者先经过v,所以对先经过u,可以计算出一个区间[l,r],机场建在这个范围内对旅店i都可以接受,对v同理。所以对所有的旅店,每个旅店选一个区间,只要公共部分存在,就说明存在一段区间使机场建在这个位置对所有旅店都不超过mid。

但是直接这样写会T,因为最坏情况有2^n个区间,要剪枝:如果这两个区间有交集,说明机场对这个旅店不管建在该边上哪里都可以(两个区间一个左端点一定为0,一个右端点一定为w),所以可以不更新区间。

这样虽然能过但还是很慢,再加几个:

1、如果u和v都是旅店那找不出更优解(因为一定要先经过一个旅客中心,注意是更优不是最优),所以省掉没关系。

2、先算一下建在点上最小的答案,二分的时候以这个为上限,并且二分前先算下以上限为mid是否能接受。



//Time:86ms//Memory:0KB//Length:3401B#include <iostream>#include <cstdio>#include <cstdlib>#include <string>#include <cstring>#include <algorithm>#include <vector>#include <cmath>#include <map>#include <queue>#define MAXN 301#define MAXM 10000#define MP(x,y) make_pair(x,y)#define FI first#define SE second#define EPS 1e-6#define PDD pair<double,double>using namespace std;int dist[MAXN][MAXN];int ma[MAXN][MAXN];int uu[MAXM],vv[MAXM],ww[MAXM],th[MAXM];double ans;inline PDD npair(PDD a,PDD b){    return MP(max(a.FI,b.FI),min(a.SE,b.SE));}vector<PDD > check(int u,int v,int w,int h,double tans,vector<PDD >&ori,vector<PDD > &vec){    PDD inte1,inte2;    if(1.0*ma[u][h]*th[h]>tans-EPS) inte1=MP(1e10,-1e10);    else    if(1.0*(ma[u][h]+w)*th[h]>tans-EPS) inte1=MP(0,tans/th[h]-ma[u][h]);    else    inte1=MP(0,w);    if(1.0*ma[v][h]*th[h]>tans-EPS) inte2=MP(1e10,-1e10);    else    if(1.0*(ma[v][h]+w)*th[h]>tans-EPS) inte2=MP(0,tans/th[h]-ma[v][h]);    else    inte2=MP(0,w);    inte2.FI=w-inte2.FI,inte2.SE=w-inte2.SE;    swap(inte2.FI,inte2.SE);    if(inte1.SE>inte2.FI-EPS)        inte1=MP(0,w),        inte2=MP(1e10,-1e10);    for(int i=0;i<ori.size();++i)    {        PDD tmp;        if(inte1.FI<inte1.SE+EPS)        {            tmp=npair(inte1,ori[i]);            if(tmp.FI<tmp.SE)                vec.push_back(tmp);        }        if(inte2.FI<inte2.SE+EPS)        {            tmp=npair(inte2,ori[i]);            if(tmp.FI<tmp.SE)                vec.push_back(tmp);        }    }    return vec;}bool cal(double mid,int n,int u,int v,int w){    int s=0;    vector<PDD > interval[2];    interval[s].push_back(MP(0,w));    for(int i=1;i<=n;++i)    {        interval[!s].clear();        check(u,v,w,i,mid,interval[s],interval[!s]);        s=!s;        if(interval[s].size()==0)  return false;    }    return true;}double mfind(int u,int v,int w,int n){    double l=0,mid,ret=1e100,r=ans;    mid=ans;    if(!cal(mid,n,u,v,w)) return ret;    while(l<r-EPS)    {        mid=(l+r)/2;        if(cal(mid,n,u,v,w))            r=ret=mid;        else            l=mid;    }    return ret;}int main(){    //freopen("H:\\MyDocument\\Code\\input.txt","r",stdin);    int n,k,m;    while(scanf("%d%d%d",&n,&k,&m)==3)    {        if(!n&&!k&&!m)  break;        memset(dist,0x3f,sizeof(dist));        memset(ma,0x3f,sizeof(ma));        for(int i=1;i<=n+k;++i) dist[i][i]=0;        for(int i=0;i<m;++i)            scanf("%d%d%d",&uu[i],&vv[i],&ww[i]),            dist[uu[i]][vv[i]]=dist[vv[i]][uu[i]]=ww[i];        for(int l=1;l<=n+k;++l)            for(int i=1;i<=n+k;++i)                for(int j=1;j<=n+k;++j)                    dist[i][j]=min(dist[i][l]+dist[l][j],dist[i][j]);        for(int l=n+1;l<=n+k;++l)            for(int i=1;i<=n+k;++i)                for(int j=1;j<=n;++j)                    ma[i][j]=min(ma[i][j],dist[i][l]+dist[l][j]);        for(int i=1;i<=n;++i)            scanf("%d",&th[i]);        ans=1e100;        for(int i=1;i<=n+k;++i)        {            double tmp=0;            for(int j=1;j<=n;++j)   tmp=max(tmp,1.0*th[j]*ma[i][j]);            ans=min(ans,tmp);        }        for(int i=0;i<m;++i)            if(uu[i]>n||vv[i]>n)                ans=min(ans,mfind(uu[i],vv[i],ww[i],n));        printf("%.3f\n",ans);    }    return 0;}