版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38083668/article/details/82919075
题目背景
NOIP2001提高组第四题。
题目描述
又到暑假了,住在城市 A 的 Car 想和朋友一起去城市 B 旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为 Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为 t。
图例:
那么 Car 应如何安排到城市 B 的路线才能尽可能的节省花费呢?请你编程帮她找出一条从城市 A 到 B 的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少,小数点后保留 2 位。
输入格式
第一行为一个正整数 n(0<=n<=10),表示有 n 组测试数据。
每组的第一行有四个正整数 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 个城市中任意三个机场的坐标,Ti为第 i 个城市高速铁路单位里程的价格。
输出格式
输出共有 n 行,每行一个数据对应相应测试数据的输出结果,即总的最小花费。
样例数据 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
输出
47.55
解析:
最短路。
最短路很明显,只需要细心一点就行了,唯一需要说一下的就是对于输入的每个城市的三个机场,如何求出第四个机场的坐标?
因为保证是矩形,所以只需要通过向量法求出两个直角边,就可以确定矩形了。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
const int Maxn=405;
const int Maxm=220000;
int q,n,size,S,T;
int first[Maxn],vis[Maxn];
double ans=1e9,m,dis[Maxn],t[Maxn],x[Maxn],y[Maxn];
struct shu{int to,next;double len;};
shu edge[Maxm<<1];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void clean()
{
size=0;
for(int i=1;i<=n*4;i++) first[i]=0;
}
inline void cal(int id,double x1,double y1,double x2,double y2,double x3,double y3)
{
x[(id-1)*4+4]=x1+x3-x2;
y[(id-1)*4+4]=y1+y3-y2;
}
inline void Q(int id)
{
double x1=x[(id-1)*4+1],y1=y[(id-1)*4+1];
double x2=x[(id-1)*4+2],y2=y[(id-1)*4+2];
double x3=x[(id-1)*4+3],y3=y[(id-1)*4+3];
if((x1-x2)*(x3-x2)+(y1-y2)*(y3-y2)==0) cal(id,x1,y1,x2,y2,x3,y3);
if((x1-x3)*(x2-x3)+(y1-y3)*(y2-y3)==0) cal(id,x1,y1,x3,y3,x2,y2);
if((x3-x1)*(x2-x1)+(y3-y1)*(y2-y1)==0) cal(id,x3,y3,x1,y1,x2,y2);
}
inline double calc(int i,int j)
{
return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
inline void build(int x,int y,double z)
{
edge[++size].next=first[x];
first[x]=size;
edge[size].to=y,edge[size].len=z;
}
inline void pre()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=4;j++)
for(int k=1;k<=4;k++)
{
if(j==k) continue;
double len=calc((i-1)*4+j,(i-1)*4+k)*t[i];
build((i-1)*4+j,(i-1)*4+k,len);
}
for(int j=1;j<=n;j++)
{
if(i==j) continue;
for(int k=1;k<=4;k++)
for(int l=1;l<=4;l++)
{
double len=calc((i-1)*4+k,(j-1)*4+l)*m;
build((i-1)*4+k,(j-1)*4+l,len);
}
}
}
}
inline double mn(double x,double y){return x<y?x:y;}
inline void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
priority_queue<pair<double,int> >q;
q.push(make_pair(0.0,s));dis[s]=0.0;
while(q.size())
{
int point=q.top().second;q.pop();
if(vis[point]) continue;vis[point]=1;
for(int u=first[point];u;u=edge[u].next)
{
int to=edge[u].to;
if(dis[to]>dis[point]+edge[u].len)
{
dis[to]=dis[point]+edge[u].len;
q.push(make_pair(-dis[to],to));
}
}
}
}
inline void solve()
{
for(int i=1;i<=4;i++)
{
for(int j=1;j<=n*4;j++) dis[j]=1e9;
dijkstra((S-1)*4+i);
for(int j=1;j<=4;j++) ans=mn(ans,dis[(T-1)*4+j]);
}
}
int main()
{
q=get_int();
while(q--)
{
n=get_int(),m=get_int(),S=get_int(),T=get_int();
clean();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=3;j++) x[(i-1)*4+j]=get_int(),y[(i-1)*4+j]=get_int();
Q(i);
t[i]=get_int();
}
pre();
solve();
printf("%.2lf\n",ans);
}
return 0;
}