VIJOS P1119 (NOIP2001 Problem4):Car的旅行路线 Accepted

描述 Description  
    又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。
  那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。
   
   
 输入格式 Input Format 
    第一行有四个正整数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 Format 
  输出最小费用(结果保留两位小数)

 

最短路问题,用Dijkstra算法可以完美解决。

难点在于建图。

假设未知坐标为p4(x4,y4),已知坐标分别是p1(x1,y1) p2(x2,y2) p3(x3,y3)

先根据垂直向量积为零判断每个矩形缺失的坐标位置,如果p1是p4的对角,则

(x3-x1)(x2-x1)+(y3-y1)(y2-y1)=0

由中点公式易知

x4=x3+x2-x1

y4=y3+y2-y1

下面可以开始构图了。

我构图的方案是以城市为单位,先计算内部火车线路之间的边权(火车价格*距离),然后计算该城市各机场与其他城市每一个机场之间的边权(飞机单价*距离)。这样完成以后就得到一张稠密的无向图。剩下的工作就是最短路径的标程了。

还值得注意的一点是,Dijkstra开始的时候应该把起始城市的4个机场最短距离都设为0。

 

#include < stdio.h >
#include
< math.h >
#include
< stdbool.h >
#define  BIG 999999.0

void  Dijkstra( void );
float  dist( float  x1, float  y1, float  x2, float  y2);
void  construct( void );

typedef 
struct
{
        
float x,y;
}
Point;
Point ct[
100 ][ 4 ];
int  rail[ 100 ];
int  s,t,a,b;
float  dis[ 100 ];
float  g[ 400 ][ 400 ];

int  main( void )
{
        
int i,j,k;
        
float answer=BIG;
        FILE 
*fin=stdin; 
        fscanf(fin,
"%d %d %d %d ",&s,&t,&a,&b);
        
for(i=0;i<s;i++
                fscanf  ( 
                        fin,
"%f %f %f %f %f %f %d ",
                        
&ct[i][0].x,&ct[i][0].y,
                        
&ct[i][1].x,&ct[i][1].y,
                        
&ct[i][2].x,&ct[i][2].y,
                        
&rail[i] 
                        );
        construct();
//构图 
        Dijkstra();
        
for (i=0;i<4;i++){
                
if(dis[(b-1)*4+i]<answer) 
                answer
=dis[(b-1)*4+i];
        }

        printf(
"%.2f ",answer);
        
return 0;
}

void  construct( void )
{
        
int i,j,k,l;
        
for (i=0;i<s;i++)//计算第四个点的坐标 
                if((ct[i][1].x-ct[i][0].x)*(ct[i][2].x-ct[i][0].x)
                
+(ct[i][1].y-ct[i][0].y)*(ct[i][2].y-ct[i][0].y)==0){
                        ct[i][
3].x=ct[i][2].x+ct[i][1].x-ct[i][0].x;
                        ct[i][
3].y=ct[i][2].y+ct[i][1].y-ct[i][0].y;
                }
else if((ct[i][0].x-ct[i][1].x)*(ct[i][2].x-ct[i][1].x)
                
+(ct[i][0].y-ct[i][1].y)*(ct[i][2].y-ct[i][1].y)==0){
                        ct[i][
3].x=ct[i][2].x+ct[i][0].x-ct[i][1].x;
                        ct[i][
3].y=ct[i][2].y+ct[i][0].y-ct[i][1].y;
                }
else if((ct[i][0].x-ct[i][2].x)*(ct[i][1].x-ct[i][2].x)
                
+(ct[i][0].y-ct[i][2].y)*(ct[i][1].y-ct[i][2].y)==0){
                        ct[i][
3].x=ct[i][1].x+ct[i][0].x-ct[i][2].x;
                        ct[i][
3].y=ct[i][1].y+ct[i][0].y-ct[i][2].y;
                }

        }

        
for(i=0;i<s;i++){//以城市为单位构图 
                for(j=0;j<4;j++)//城市内部 
                        for(k=0;k<4;k++)
                                g[
4*i+j][4*i+k]=
                                rail[i]
*dist(ct[i][j].x,ct[i][j].y,ct[i][k].x,ct[i][k].y);
                
for(j=0;j<s;j++){//城市之间 
                        if(j==i)continue;
                        
for(k=0;k<4;k++)
                                
for(l=0;l<4;l++)
                                        g[
4*i+k][4*j+l]=
                                        t
*dist(ct[i][k].x,ct[i][k].y,ct[j][l].x,ct[j][l].y);
                }

        }

}

float  dist( float  x1, float  y1, float  x2, float  y2)
{
        
return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}

void  Dijkstra( void )
{
        
int i,j;
        
int min=BIG,minn;
        
bool vis[100];
        memset(vis,
0,sizeof(vis));
        
for(i=0;i<s*4;i++)
                dis[i]
=BIG;
        dis[a
-1]=dis[a]=dis[a+1]=dis[a+2]=0;
        
for(i=0;i<s*4;i++){
                min
=BIG; 
                
for(j=0;j<s*4;j++){
                        
if(!vis[j] && dis[j]<min){
                                min
=dis[j];
                                minn
=j;
                        }

                }

                vis[minn]
=true
                
for(j=0;j<4*s;j++){
                        
if(min+g[minn][j]<dis[j]) 
                                dis[j]
=dis[minn]+g[minn][j];
                }
        
        }
                
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值