NOIP 2001 T4
原题地址:
https://www.luogu.org/problem/show?pid=1027
最短路Floyd 计算几何
解题思路
说白了就是一个稠密图的最短路问题,图稠密到每两个点之间都有连边,所以跑floyd又安全又好打,虽然数据太水spfa啥的也能跑过,但毕竟题目给的数据范围还是挺吓人的,最好别以身试毒冒险。然而这个题的关键不在于最短路怎么打,而是初始化,再往前延伸就是这巨坑无比的数据读入格式怎么转化成有效信息……
Point.1 坐标存储
是的,这个题的数据读入简直是简直了……给出矩形的三个顶点坐标求剩下那个的坐标,数学渣表示一脸懵逼……于是参考了cgk大神的blog,瞬间觉得被耍了……
Point.2 数组初始化
说是整道题最核心的部分也不为过(当然如果point.1解决不了剩下的都是浮云)。总之就是一个城市有四个点,两两连边,边权为距离*车费;分属不同城市的点两两连边,边权为距离*飞机票钱。
Point.3 floyd
最简单的最短路算法,三重循环O(n^3)。数据太水(只有5个点而且远没有到题干上给出的数据范围那么大,所以这种其实时间复杂度很高的算法也不会T)
参考代码(有点复杂凑合着看吧)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
using namespace std;
int x[15][5],y[15][5],t[105];
double dist[500][500];
struct mc1
{
int x,y;
}e[500];
struct mc2
{
int pos[5];
}q[105];
double dis(int x1,int y1,int x2,int y2)
{
returnsqrt((double)((x2-x1)*(x2-x1))+(double)((y2-y1)*(y2-y1)));
}
double max_(double x,double y,double z)
{
double re=x;
if (y>re) re=y;
if (z>re) re=z;
return re;
}
int main()
{
int n;
cin>>n;
int s,p,a,b;
cin>>s>>p>>a>>b;
int cnt=0;
for (inti=1;i<=s;i++)
{
cin>>x[i][1]>>y[i][1]>>x[i][2]>>y[i][2]>>x[i][3]>>y[i][3]>>t[i];
doublep1=dis(x[i][1],y[i][1],x[i][2],y[i][2]);
doublep2=dis(x[i][1],y[i][1],x[i][3],y[i][3]);
doublep3=dis(x[i][2],y[i][2],x[i][3],y[i][3]);
double mx=max_(p1,p2,p3);//求第四个顶点的坐标;
if (mx==p1)
{
x[i][4]=x[i][1]+x[i][2]-x[i][3];
y[i][4]=y[i][1]+y[i][2]-y[i][3];
}
if (mx==p2)
{
x[i][4]=x[i][1]+x[i][3]-x[i][2];
y[i][4]=y[i][1]+y[i][3]-y[i][2];
}
if (mx==p3)
{
x[i][4]=x[i][2]+x[i][3]-x[i][1];
y[i][4]=y[i][2]+y[i][3]-y[i][1];
}
for (intj=1;j<=4;j++) //加点;
{
cnt++;
e[cnt].x=x[i][j];
e[cnt].y=y[i][j];
q[i].pos[j]=cnt; //记录每个城市包含的点;
for (intk=0;k<j;k++) //城市内部点之间连边;
{
dist[cnt][cnt-k]=dis(e[cnt].x,e[cnt].y,e[cnt-k].x,e[cnt-k].y)*t[i];
dist[cnt-k][cnt]=dist[cnt][cnt-k];
}
}
for (intj=1;j<=cnt-4;j++) //不同城市的点之间连边;
{
intsx=e[j].x,sy=e[j].y;
for (intk=0;k<=3;k++) //这一重循环一定要在上一重里面,不能提出去用,这个(2,+ ∞)的bug卡了我半小时TAT……
{
intrx=e[cnt-k].x,ry=e[cnt-k].y;
dist[j][cnt-k]=dis(sx,sy,rx,ry)*p;
dist[cnt-k][j]=dist[j][cnt-k];
}
}
}
//floyd算法:
for (intk=1;k<=cnt;k++)
for (int i=1;i<=cnt;i++)
for (intj=1;j<=cnt;j++)
dist[i][j]=min(dist[i][k]+dist[k][j],dist[i][j]);
double mi=210000000;
//枚举出发城市和目的城市的点,取最小值:
for (inti=1;i<=4;i++)
{
int t1=q[a].pos[i];
for (int j=1;j<=4;j++)
{
int t2=q[b].pos[j];
if(dist[t1][t2]<mi) mi=dist[t1][t2];
}
}
printf("%.1f",mi); //注意精度;
return 0;
}