wikioi-天梯-提高一等-最短路-1041:Car的旅行路线

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

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

第一行为一个正整数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个城市高速铁路单位里程的价格。

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

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.5

类型:图论  难度:2

题意:给定s个机场,每个机场是个矩形,给出其中任意三个点的坐标,每个机场的四个点两两之间有公路,给出每个机场的6条公路的单位价格ti,机场之间的航线的单位价格为t,求从机场A到机场B的最小价格。

分析:

1、先求出每个矩形的第四个点的坐标,方法是先找到三个点中距离最大的两个点,即为对角线,若12为对角线,34为对角线,那么x1+x2=x3+x4,y1+y2=y3+y4,即可求出第四个点的坐标。

2、求出任意两点的直接连接的价格,若为一个机场内的点,则为dis*ti,若为两个机场的点,则为dis*t

3、遍历机场A的四个点,分别用dij方法计算其到机场B的四个点的最短路,取最小的,即为结果

注意:

1、dij方法计算单源最短路:设求点i到其他所有点最短路,那么先找到和点i距离最近的点,如j,置定j,遍历j的邻点k,若d[i][k]>d[i][j]+d[j][k],证明经过点j,i和k的距离变小,更新d[i][k]。然后继续下一循环,直到找到终点。

2、用一个标记数组f[i][j]记录已经计算出的最短路的点,若f[i][j]=1,则i到j的最短路已经算出。防止重复计算。

 

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
using namespace std;

int s,t,a,b;
double pos[110][4][2],ti[110],w[110][4][110][4];
bool f[110][4][110][4];

void callastp(double m[][2])
{
    double d01,d02,d12,d;
    int a1,a2,b;
    d01 = pow(m[0][0]-m[1][0],2)+pow(m[0][1]-m[1][1],2);
    d02 = pow(m[0][0]-m[2][0],2)+pow(m[0][1]-m[2][1],2);
    d12 = pow(m[1][0]-m[2][0],2)+pow(m[1][1]-m[2][1],2);
    
    if(d01>=d02 && d01>=d12)
    {
        a1 = 0;
        a2 = 1;
        b = 2;
    }
    if(d02>=d01 && d02>=d12)
    {
        a1 = 0;
        a2 = 2;
        b = 1;
    }
    if(d12>=d02 && d12>=d01)
    {
        a1 = 1;
        a2 = 2;
        b = 0;
    }
    
    m[3][0] = m[a1][0]+m[a2][0]-m[b][0];
    m[3][1] = m[a1][1]+m[a2][1]-m[b][1];
}

double caldis(double x[], double y[])
{
    return sqrt(pow(x[0]-y[0],2)+pow(x[1]-y[1],2));
}

double dij(int m,int x,int n,int y)
{
    if(m==n)
        return 0;
    if(f[m][x][n][y])
        return w[m][x][n][y];
    
    bool ch[110][4];
    memset(ch,0,sizeof(ch));
    
    while(1)
    {
        int mini,minj,minn;
        mini = minj = minn = -1;
        for(int i=1; i<=s; i++)
        {
            for(int j=0; j<4; j++)
            {
                if(i==m && j==x)
                    continue;
                if(ch[i][j]) 
                    continue;
                if(minn<0 || w[m][x][i][j]<minn)
                {
                    minn = w[m][x][i][j];
                    mini = i;
                    minj = j;
                }
            }
        }
        f[m][x][mini][minj] = 1;
        ch[mini][minj] = 1;
        if(mini==n && minj==y)
        {
            //cout<<m<<" "<<x<<" "<<n<<" "<<y<<" "<<w[m][x][n][y]<<endl;
            return w[m][x][n][y];
        }
        for(int i=1; i<=s; i++)
        {
            for(int j=0; j<4; j++)
            {
                if(w[m][x][mini][minj]+w[mini][minj][i][j]<w[m][x][i][j])
                {
                    w[m][x][i][j] = w[m][x][mini][minj]+w[mini][minj][i][j];
                }
            }
        }
    }
}

int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        cin>>s>>t>>a>>b;
        for(int i=1; i<=s; i++)
        {
            for(int j=0; j<3; j++)
                cin>>pos[i][j][0]>>pos[i][j][1];
            cin>>ti[i];
            
            callastp(pos[i]);
            //cout<<pos[i][3][0]<<" "<<pos[i][3][1]<<endl;
        }
        memset(w,0,sizeof(w));
        for(int i=1; i<=s; i++)
        {
            for(int j=0; j<4; j++)
            {
                for(int k=j+1; k<4; k++)
                    w[i][j][i][k] = w[i][k][i][j] = caldis(pos[i][j],pos[i][k])*ti[i];
                for(int k=i+1; k<=s; k++)
                    for(int l=0; l<4; l++)
                        w[i][j][k][l] = w[k][l][i][j] = caldis(pos[i][j],pos[k][l])*t;
            }
        }
        memset(f,0,sizeof(f));
        double ans = -1;
        for(int i=0; i<4; i++)
        {
            for(int j=0; j<4; j++)
            {
                if(!f[a][i][b][j])
                    dij(a,i,b,j);
                if(ans<0 || w[a][i][b][j]<ans)
                    ans = w[a][i][b][j];
            }
        }
        cout<<fixed<<showpoint<<setprecision(1)<<ans<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值