【问题描述】
又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。
那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。
任务:找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。
【输入格式】
第一行有一个整数K,表示有K组数据
第二行有四个正整数s,t,A,B。S(0 接下来有S行,其中第i行均有7个正整数x1,y1,x2,y2,x3,y3,T,这当中的(x1,y1),(x2,y2),(x3,y3)分别是第i个城市中任意三个机场的坐标,T 为第i个城市高速铁路单位里程的价格。
【输出格式】
共有n行,每行一个数据对应测试数据。输出最小费用,小数点后保留2位。
【输入样例】
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
【数据范围】
0
分析:
这个题模板很直观,可能卡也就卡在找第四个直角上。
建图顺带一提,首先,同一个矩形内只能连高速铁路;其次,不同的矩形之间连接飞机航线;
还是得说说找第四个直角的方法,我是通过斜率的公式来找的:枚举这三个点把哪个当做直角,设三个角A,B,C,其中C是第四个直角,然后根据斜率的公式分别算出直线AC和直线AB的斜率,然后看相乘是不是等于-1.....可以自己推一推,其实高中也会讲;注意的是,当这个矩形的边与x轴,y轴平行时注意斜率为0和斜率不存在的情况(分母为0)感觉应该可以有更简便的方法...
然后连好之后,在起点的矩形四个角上分别做一次最短路算法,求最小的就可以了。
在确定直角的时候可以自己打一下草稿
#include
#include
#include
#include
using namespace std;
typedef double DB;
const int maxn=105;
const DB INF=100000000;
int K,s,t,n,A,B,np,last[maxn*4],cost[maxn];
struct edge{int to,pre;DB w;}E[maxn*4*maxn*4];
struct point{int x,y;}P[maxn*4];
struct data
{
DB d;int id;
friend bool operator < (data a,data b) {return a.d>b.d;}
};
char c;
inline void qkscanf(int &x)
{
for(c=getchar();c<'0'||c>'9';c=getchar());
for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
}
inline void init()
{
for(int i=1;i<=n*4;i++) last[i]=0;
n=0,np=0;
}
inline bool check(point a,point b,point c)
{
if((a.y==c.y&&b.x==c.x)||(a.x==c.x&&b.y==c.y)) return 1;//有一条直线与坐标轴平行
if(a.y==c.y||a.x==c.x||b.x==c.x||b.y==c.y) return 0;//如果一条直线与坐标轴平行但另一条不平行,行不通
return (a.x-c.x)*(b.x-c.x)/(a.y-c.y)/(b.y-c.y)==-1;//两个斜率相乘为-1
}
inline point findp(point a,point b,point c)
{
int x=a.x+b.x-c.x,y=a.y+b.y-c.y;//如果已知c是直角,那么有Xa+Xb=Xc+Xd,Y类似
return (point){x,y};
}
inline DB DIST(int a,int b,int k)
{
DB dis=sqrt((DB)(P[a].x-P[b].x)*(P[a].x-P[b].x)+(DB)(P[a].y-P[b].y)*(P[a].y-P[b].y));
return dis*(DB)k;
}
inline void addedge(int u,int v,DB dis)
{
E[++np]=(edge){v,last[u],dis};
last[u]=np;
}
int done[maxn*4];
DB dist[maxn*4];
inline void Dijkstra(int s)
{
priority_queuepq;
for(int i=0;i<=n;i++) done[i]=0,dist[i]=INF;
dist[s]=0;
pq.push((data){0,s});
while(!pq.empty())
{
data t=pq.top();pq.pop();
int i=t.id;
if(done[i]) continue;
done[i]=1;
for(int p=last[i];p;p=E[p].pre)
{
int j=E[p].to;
DB w=E[p].w;
if(dist[j]>dist[i]+w)
{
dist[j]=dist[i]+w;
pq.push((data){dist[j],j});
}
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
qkscanf(K);
while(K--)
{
qkscanf(s);qkscanf(t);qkscanf(A);qkscanf(B);
init();
int T;
point a1,a2,a3,a4;
for(int i=1;i<=s;i++)//先把每个点存起来
{
qkscanf(a1.x);qkscanf(a1.y);
qkscanf(a2.x);qkscanf(a2.y);
qkscanf(a3.x);qkscanf(a3.y);
P[n++]=a1,P[n++]=a2,P[n++]=a3;
if(check(a1,a2,a3)) a4=findp(a1,a2,a3);
else if(check(a1,a3,a2)) a4=findp(a1,a3,a2);
else a4=findp(a2,a3,a1);
P[n++]=a4;
qkscanf(cost[i]);
}
register int a,b;
for(int i=1;i<=s;i++)//注意建边
{
for(int k1=0;k1<4;k1++)
{
a=(i-1)*4+k1;
for(int k2=k1+1;k2<4;k2++)
{
b=(i-1)*4+k2;
DB dis=DIST(a,b,cost[i]);
addedge(a,b,dis);
addedge(b,a,dis);
}
for(int j=i+1;j<=s;j++)
{
for(int k2=0;k2<4;k2++)
{
b=(j-1)*4+k2;
DB dis=DIST(a,b,t);
addedge(a,b,dis);
addedge(b,a,dis);
}
}
}
}
DB ans=INF;
for(int i=0;i<4;i++)
{
int s=(A-1)*4+i;
Dijkstra(s);
for(int j=0;j<4;j++)
{
int k=(B-1)*4+j;
ans=min(ans,dist[k]);
}
}
printf("%.2llf\n",ans);
}
return 0;
}