[NOIP2001]Car的旅行路线

题目描述 Description

又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两 个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。

那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。
任务
找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。

输入描述 Input Description

第一行为一个正整数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个城市中任意三个机场的坐标,T I为第I个城市高速铁路单位里程的价格。

输出描述 Output Description

共有n行,每行一个数据对应测试数据。

样例输入 Sample Input

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

样例输出 Sample Output

47.5

分析

最短路的裸题= = 唯一存在的问题就是如何把“四源四终点”的最短路问题转化为复杂度较低的问题。借用刘汝佳《训练指南》上网络流建模的思路,这里不妨建立一个虚拟机场0,在0和城市A的四个机场各连一条权值为0的边,即可用单源最短路算法求解。另。。因为题目中边数E很接近n2,所以用Dijkstra会比SPFA快很多(2s和4s)。。。。别看我,我是写完SPFA之后才想起来的=_=||

 

 1  // Awsm.Definer →_→
 2  // E-Mail: willywu1998@foxmail.com
 3  #include <cstdio>
 4 #include <deque>
 5 #include <cmath>
 6 #include <memory.h>
 7 #include <iostream>
 8  #define MAX 0x3f3f3f3f
 9  #define mod(x) ( sqrt((x) * (x)) )
10  using  namespace std;
11  struct v {  // vector(location)
12       int x,y;
13     v (){};v( int a, int b):x(a),y(b){};
14     v  operator +( const v& b) { return v(x+b.x,y+b.y);}
15     v  operator -( const v& b) { return v(x-b.x,y-b.y);}
16      int  operator * ( const v& b) { return x*b.x + y*b.y;}
17 };
18 inline v get4(v &p1,v &p2,v &p3) {
19      if((p2 - p1) * (p3 - p1) ==  0return p2 - p1 + p3;
20      if((p1 - p2) * (p3 - p2) ==  0return p1 - p2 + p3;
21      return p1 - p3 + p2;
22 }
23 inline  void getv(v &k) {
24     scanf( " %d%d ",&k.x,&k.y);
25 }
26  int n,s,t,A,B;  // the meaning of s will be changed in function "work"...
27  double dis[ 404][ 404]={ 0};
28 inline  void makegragh() {  // build dis[][]
29      v p[ 404];
30      int Ti;
31      for( int i= 1;i<=s;i+= 4) {
32         getv(p[i]),getv(p[i+ 1]),getv(p[i+ 2]);scanf( " %d ",&Ti);
33         p[i+ 3]=get4(p[i],p[i+ 1],p[i+ 2]);
34          for( int j= 0;j< 3;++j) for( int k=j;k< 4;++k)
35             dis[i+j][i+k]=dis[i+k][i+j]=Ti * mod((p[i+k]-p[i+j]));
36          for( int j= 1;j<i;++j) for( int k= 0;k< 4;++k)
37             dis[j][i+k]=dis[i+k][j]=t * mod((p[i+k]-p[j]));
38     }
39 }
40 inline  double SPFA() { 
41     deque < int> Q;
42      int k =  4 * A -  3,K =  4 * B -  3;
43     Q.push_front(k),Q.push_front(k+ 1),Q.push_front(k+ 2),Q.push_front(k+ 3);
44      bool in_Q[ 404] = { 0};in_Q[k]=in_Q[k+ 1]=in_Q[k+ 2]=in_Q[k+ 3]= 1;
45      double cost[ 404];
46      int i,t;
47      for(i= 1;i<=s;++i) cost[i] = MAX;
48     cost[k]=cost[k+ 1]=cost[k+ 2]=cost[k+ 3]= 0;
49      while(!Q.empty()) {
50         t = Q.front(); Q.pop_front(); in_Q[t] =  0;
51          for(i =  1;i <= s;++i) {
52              if(i==t) continue;
53              if(cost[i] > cost[t] + dis[i][t]) {  // relax
54                  cost[i] = cost[t] + dis[i][t];
55                  if(in_Q[i]) continue;
56                  if(Q.empty() || cost[Q.front()] < cost[i])Q.push_back(i);
57                  else Q.push_front(i);
58                 in_Q[i] =  1;
59             }
60         }
61     }
62      return min(min(cost[K],cost[K+ 1]),min(cost[K+ 2],cost[K+ 3]));
63 }
64  void work() {
65     scanf( " %d%d%d%d ",&s,&t,&A,&B);s *=  4; // s -> sum of airports
66      makegragh();
67     printf( " %.1f\n ", SPFA());  // (0) -> (4*n+1)
68  }
69  int main(){
70     #ifdef DEBUG
71     freopen( " test.in ", " r ",stdin);
72      #endif
73     scanf( " %d ",&n);
74      while(n--)
75         work();
76      return  0;
77 }

转载于:https://www.cnblogs.com/Asm-Definer/p/3912640.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值