描述
又到暑假了,住在城市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;}