算法训练 Car的旅行路线 蓝桥杯

描述

又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。

那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。

格式

输入格式

第一行有四个正整数s,t,A,B。S(0<S<=100)表示城市的个数,t表示飞机单位里程的价格,A,B分别为城市A,B的序号,(1<=A,B<=S)。

接下来有S行,其中第I行均有7个正整数xi1,yi1,xi2,yi2,xi3,yi3,Ti,这当中的(xi1,yi1),(xi2,yi2),(xi3,yi3)分别是第I个城市中任意三个机场的坐标,T I为第I个城市高速铁路单位里程的价格。

输出格式

输出最小费用(结果保留两位小数)

样例1

样例输入1

3 10 1 3
1 1 1 3 3 1 30
2 5 7 4 5 2 1
8 6 8 8 11 6 3

样例输出1

47.55

限制

每个测试点1s

最短路径问题之两点最短路径

Floryd—Warshall算法

要理解这个算法先要了解Floyd算法

Floyd算法的核心是dp[k][i][j],意思是从i到j,中间使用前k个节点或是不用节点,得到的最短边权和。

递推式dp[k][i][j]=min(dp[k-1][i][j],dp[k-1][i][k]+dp[k-1][k][j])

整个过程就是在维护n个表,每个表记录使用前k个节点得到的最优值。

通常可以在任何图使用,包括有向图,负权图。

F-W算法简化了算法,使用一张表完成n张表的任务,每次更新都要使用前面那个表k行k列的数据,而更新对k行k列数据不产生影响,所以这种简化可行。

这道题还有其他特性,在代码里注释了。

时间复杂度O(n^3),空间复杂度O(n^2)

#include <cstring>
#include <cstdio>
#include<cmath>
#include <queue>
#include<algorithm>
using namespace std;
#define min(a,b) ((a<b)?(a):(b))
#define swap(a,b) temp=a;a=b;b=temp
const float INF=99999.9999;
void deter(float x1,float y1,float x2,float y2,float x3,float y3,float *x,float *y){
    float temp;
    if((x1-x2)*(x3-x2)+(y1-y2)*(y3-y2)==0){//判断哪个点是直角点
        swap(x1,x2);swap(y1,y2);
    }
    else if((x1-x3)*(x2-x3)+(y1-y3)*(y2-y3)==0){
        swap(x1,x3);swap(y1,y3);
    }
    *x=x2+x3-x1;
    *y=y2+y3-y1;
    }
struct city{
float x[4];
float y[4];
float T;
city(float x1,float y1,float x2,float y2,float x3,float y3,float t){
x[0]=x1;x[1]=x2;x[2]=x3;
y[0]=y1;y[1]=y2;y[2]=y3;
deter(x1,y1,x2,y2,x3,y3,&x[3],&y[3]);
T=t;
}
}*c[1010];
float dp[410][410];
float dist(float x1,float y1,float x2,float y2){
return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
void init(int s,float t){
  int i,j;
  for(i=0;i<4*s;i++){//建立下标与点构建关系:i/4==城市编号,i%4==点在城市内的编号
    for(j=0;j<4*s;j++){
        if(i/4==j/4){
            dp[i][j]=dist(c[i/4]->x[i%4],c[i/4]->y[i%4],c[j/4]->x[j%4],c[j/4]->y[j%4])*c[i/4]->T;
        }
        else{
            dp[i][j]=dist(c[i/4]->x[i%4],c[i/4]->y[i%4],c[j/4]->x[j%4],c[j/4]->y[j%4])*t;
        }
    }
  }
}
void FW(int s){
for(int k=0;k<4*s;k++){
    for(int i=0;i<4*s;i++){
        for(int j=0;j<4*s;j++){
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
        }
    }
}
}
int main(){
int A,B;
int s;
float t,co;
float x1,x2,x3,y1,y2,y3;
    memset(dp,0,sizeof(dp));
    scanf("%d%f%d%d",&s,&t,&A,&B);
    for(int i=0;i<s;i++){
        scanf("%f%f%f%f%f%f%f",&x1,&y1,&x2,&y2,&x3,&y3,&co);//注意使用float,用double的话,1储存为-0,00
        c[i]=new city(x1,y1,x2,y2,x3,y3,co);
    }
    init(s,t);
    FW(s);
    float q=INF;
    for(int i=4*A-4;i<4*A;i++)//A,B是城市编号,不是点在表格里的编号
        for(int j=4*B-4;j<4*B;j++)
        q=min(q,dp[i][j]);
    printf("%.1f",q);
    for(int i=0;i<s;i++){
        delete c[i];
}
return 0;}



    原文作者:旅游交通路线问题
    原文地址: https://blog.csdn.net/sinat_35637319/article/details/56676968
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞