题解 P1027 【Car的旅行路线】
ShineEternal
2019-08-27 07:42:28
这道题代码可真的不简单。。
## 题目链接:
https://www.luogu.org/problem/P1027
## 分析:
**注:这里面的点指机场而非城市**
这道题乍一看题目描述不难,其实就是一个最短路问题,不过就是起点可能有多个,终点也有多个,所以我们跑个Floyd就行。
- 但因为我怕$O(n^3)$跑不起,所以换成了$n$遍$dijkstra$(这里n☞点数)
所以时间复杂度为:$O(n^2log_n)$
- (dij用了堆优化
### 然后我们来到样例,发现还有毒瘤的预处理。
样例无良的给了矩形的三个点,说明第四个点可以根据前三个求出。
- 于是我们考虑到运用矩形对角线的一些性质。
- 首先找出距离最远的两个点(三个点中)
- 然后连线取中点(当然编程中不用连线那一步操作)
- 再将另外的第3个点(不在连线的两端)向中点连线,延长即可
```cpp
void find(double a,double b,double c,double d,double e,double f)//读入三个点的坐标,跑完函数就把第四个点的值赋完了
{
cnt++;
dis[1].num=sqrt(Sqr(a-c)+Sqr(b-d));
dis[1].id=1;
dis[2].num=sqrt(Sqr(e-c)+Sqr(f-d));
dis[2].id=2;
dis[3].num=sqrt(Sqr(a-e)+Sqr(b-f));
dis[3].id=3;
sort(dis+1,dis+4,cmp);
if(dis[1].id==1)
{
double x=min(a,c)+Abs(a-c)/2;
double y=min(b,d)+Abs(b-d)/2;
double xn=x+x-e;
double yn=y+y-f;
p[cnt].x=xn;
p[cnt].y=yn;
}
if(dis[1].id==2)
{
double x=min(c,e)+Abs(e-c)/2;
double y=min(f,d)+Abs(f-d)/2;
double xn=x+x-a;
double yn=y+y-b;
p[cnt].x=xn;
p[cnt].y=yn;
}
if(dis[1].id==3)
{
double x=min(a,e)+Abs(a-e)/2;
double y=min(b,f)+Abs(b-f)/2;
double xn=x+x-c;
double yn=y+y-d;
p[cnt].x=xn;
p[cnt].y=yn;
}
}
```
这样,就处理完了,最后,我们发现其实任意两点都有连接(要不航线要不铁路),所以处理出距离,在判断是否在一个城市,就可以找到每条路的价值。
- 跑dij即可
- 别忘了给点所在的城市打标记,这样最后方便找A和B
**这里引申出了一个惨痛的教训:结构体的存储方式要想好**
刚开始我是以一个城市为一个结构体,然后就特别难写,最后只好重构代码
## $code:$
```cpp
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define pa pair<double,int>
int vis[4005];
priority_queue<pa,vector<pa>,greater<pa> > q;
struct point
{
double x,y,T;
int id;
}p[4005];
struct D
{
double id;
double num;
}dis[4];
double Sqr(int x)
{
return x*x;
}
double cmp(const D &a,const D &b)
{
return a.num>b.num;
}
double Abs(double x)
{
if(x<0)return -x;
return x;
}
int cnt=0;
void find(double a,double b,double c,double d,double e,double f)
{
cnt++;
dis[1].num=sqrt(Sqr(a-c)+Sqr(b-d));
dis[1].id=1;
dis[2].num=sqrt(Sqr(e-c)+Sqr(f-d));
dis[2].id=2;
dis[3].num=sqrt(Sqr(a-e)+Sqr(b-f));
dis[3].id=3;
sort(dis+1,dis+4,cmp);
if(dis[1].id==1)
{
double x=min(a,c)+Abs(a-c)/2;
double y=min(b,d)+Abs(b-d)/2;
double xn=x+x-e;
double yn=y+y-f;
p[cnt].x=xn;
p[cnt].y=yn;
}
if(dis[1].id==2)
{
double x=min(c,e)+Abs(e-c)/2;
double y=min(f,d)+Abs(f-d)/2;
double xn=x+x-a;
double yn=y+y-b;
p[cnt].x=xn;
p[cnt].y=yn;
}
if(dis[1].id==3)
{
double x=min(a,e)+Abs(a-e)/2;
double y=min(b,f)+Abs(b-f)/2;
double xn=x+x-c;
double yn=y+y-d;
p[cnt].x=xn;
p[cnt].y=yn;
}
}
double d[405][405],dist[405][405];
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
d[s][s]=0;
q.push(make_pair(0,s));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x]==1)
continue;
vis[x]=1;
for(int i=1;i<=cnt;i++)
{
if(d[s][x]+dist[x][i]<d[s][i])
{
d[s][i]=d[s][x]+dist[x][i];
q.push(make_pair(d[s][i],i));
}
}
}
}
int main()
{
double t;
int N,A,B,s;
scanf("%d",&N);
while(N--)
{
cnt=0;
scanf("%d%lf%d%d",&s,&t,&A,&B);
int city=0;
for(int i=1;i<=s;i++)
{
city++;
for(int j=1;j<=3;j++)
{
cnt++;
scanf("%lf%lf",&p[cnt].x,&p[cnt].y);
p[cnt].id=city;
}
scanf("%lf",&p[cnt].T);
p[cnt-2].T=p[cnt].T;
p[cnt-1].T=p[cnt].T;
p[cnt+1].T=p[cnt].T;
//printf("%lf %lf\n",p[cnt-j+1].x,p[cnt-j+1].y);
find(p[cnt-2].x,p[cnt-2].y,p[cnt-1].x,p[cnt-1].y,p[cnt].x,p[cnt].y);
p[cnt].id=city;
//printf("i=%lf %lf\n",p[cnt].x,p[cnt].y);
}
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=cnt;j++)
{
double tmp=sqrt(Sqr(p[i].x-p[j].x)+Sqr(p[i].y-p[j].y));
if(p[i].id==p[j].id)
{
dist[i][j]=tmp*p[i].T;
}
else
{
dist[i][j]=tmp*t;
}
}
}
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=cnt;j++)
{
d[i][j]=2147483640;
}
}
for(int i=1;i<=cnt;i++)
{
dijkstra(i);
}
double ans=2147483640;
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=cnt;j++)
{
if(p[i].id==A&&p[j].id==B)
{
if(d[i][j]<ans)
{
ans=d[i][j];
}
//ans=min(ans,d[i][j]);
}
}
}
printf("%.1lf\n",ans);
}
return 0;
}
```