UVAlive 5869 Airport 解题报告

题目

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;
}

你可能感兴趣的:(UVAlive 5869 Airport 解题报告)