P1027 [NOIP2001 提高组] Car 的旅行路线

本题我们不妨把每个城市的4个机场看做四个点。那样这图就有4×s4×s 个点。

根据题目描述,我们又知道:每一个机场都与另外每一个机场互通,差别只是在是否是同一个城市:

如果是,那么只能走高速铁路;

如果不是,那么只能走航道。用一个判断来计算这条路的花费即可。

最后跑最短路,答案为到达城市的4个机场的花费的最小值。

C++:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;

struct data {
    int x,y; //(x,y)
    int city; // 所在城市
};

const int maxn=100;
int s,t,A,B;
int T[maxn+1];
double dis[maxn<<2|1];
data a[maxn<<2|1];

int pingfang(int x) { return x*x; }

//两点间距离公式 
double juli(int x1, int y1, int x2, int y2) { return sqrt(pingfang(x1-y1)+pingfang(x2-y2)); }

//求矩形的第四个点的函数 
void get_4th(int x1, int y1, int x2, int y2, int x3, int y3, int i) {
    //已知A(x1,y1),B(x2,y2),C(x3,y3),求D(x4,y4) 
    //ab表示AB^2,ac表示AC^2,BC表示BC^2 
    int ab=pingfang(x1-x2)+pingfang(y1-y2),
        ac=pingfang(x1-x3)+pingfang(y1-y3),
        bc=pingfang(x2-x3)+pingfang(y2-y3);
    int x4,y4;
    //用勾股定理的逆定理,判断谁是直角边 
    //再根据矩形对边平行的性质,算出第四个点的坐标 
    if (ab+ac==bc) x4=x2+x3-x1, y4=y2+y3-y1;
    if (ab+bc==ac) x4=x1+x3-x2, y4=y1+y3-y2;
    if (ac+bc==ab) x4=x1+x2-x3, y4=y1+y2-y3;
    a[i+3].x=x4;
    a[i+3].y=y4;
}

//初始化函数如题意所述 
void init() {
    memset(a,0,sizeof(a));
    scanf("%d%d%d%d",&s,&t,&A,&B);
    //对每个城市的机场进行处理 
    for (int i=1; i<=4*s; i+=4) {
        scanf("%d%d%d%d%d%d%d",&a[i].x,&a[i].y,&a[i+1].x,&a[i+1].y,&a[i+2].x,&a[i+2].y,&T[i/4+1]);
        a[i].city=a[i+1].city=a[i+2].city=a[i+3].city=i/4+1;
        //调用求出第四个点坐标的函数 
        get_4th(a[i].x,a[i].y,a[i+1].x,a[i+1].y,a[i+2].x,a[i+2].y,i);
    }
}

//最短路spfa 
void spfa() {
    //队内有没有该元素(用于加速) 
    bool mark[maxn<<2|1];
    queue <int> q;
    for (int i=1; i<=4*s; i++) dis[i]=99999999.99999;
    //可以从出发地任意一个机场出发,所以初始化都入队,并且花费均为0 
    for (int i=A*4-3;i<=A*4;i++)
        dis[i]=0, q.push(i), mark[i]=true;
    
    //bfs
    while (!q.empty()) {
        int x=q.front(); q.pop(); mark[x]=false;
        //这个机场与其余所有机场都有通路 
        for (int i=1; i<=4*s; i++) {
            if (i==x) continue;
            //花费先赋值为两点间的距离 
            double cost=juli(a[x].x,a[i].x,a[x].y,a[i].y);
            //如果两机场在同一城市,则走该城市的高速铁路 
            if (a[i].city==a[x].city) cost*=T[a[i].city];
            //否则坐飞机 
            else cost*=t;
            //如果花费更少则更新 
            if (dis[x]+cost<dis[i]) {
                dis[i]=dis[x]+cost;
                if (!mark[i])
                    mark[i]=true, q.push(i);
            }
        }
    }
}

int main() {
    int n;
    scanf("%d",&n);
    
    //有多组数据 
    while (n--) {
        init();
        spfa();
        //答案是到达地四个机场中花费最少的那个
        //用“打擂台”的方法求出最小值 
        double ans=dis[B*4];
        for (int i=B*4-3; i<B*4; i++)
            if (dis[i]<ans) ans=dis[i];
        printf("%.1lf",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值