ZOJ1064

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1064

不算难,只是代码看起来有点恶心。

首先是用Floyd求各个路口之间的最短路,储存在数组path里。

然后计算任意一个路口 i 与任意一个城市 j 之间最短路经过的第一个路口(即路口 i 和该路口之间有一条边),记录在 shortPath[i][j] 里。

最后看每个路牌,比如从 a 到 b 的路牌,如果路口 a 到人任意一个城市 j 的最短路径经过 b 的话(就是shortPath[a][j] == b),就把城市 j 列在路牌里。

(题目里说假设每对路口之间只有一个最短路径,这是一个非常重要的条件,避免了下列情况:

其中1是城市,从3到1的两条路的路程是相等的,这样shortPath[3][1]就只能记录下0,而不是2。)

#include<iostream>
#include<stdlib.h>
#include<cstdio>
#include<cstring>
#include<math.h>
using namespace std;

const int MAXN = 31;
const double ZERO = 0.0001;

struct sign
{
    int cityName, distance;
}signList[MAXN];
char city[MAXN][MAXN];

int cmp(const void *a1, const void *b1)
{
    sign* a = (sign*)a1;
    sign* b = (sign*)b1;
    if (a->distance > b->distance)
        return 1;
    else if (a->distance == b->distance)
        return strcmp(city[a->cityName], city[b->cityName]);
    else
        return -1;
}

int main()
{
    double path[MAXN][MAXN];
    double graph[MAXN][MAXN];
    int shortPath[MAXN][MAXN];
    int cityLocation[MAXN];
    int cases;

    cin>>cases;
    for (int iCase=1; iCase<=cases; iCase++)
    {
        int i, j, k;
        int a, b;
        double d;
        char name[MAXN];
        int n, m, cross;
        cin>>n>>m>>cross;
        memset(graph,0,sizeof(graph));
        memset(cityLocation,255,sizeof(cityLocation));

        for (i=0; i<m; i++)
        {
            cin>>a>>b>>d;
            graph[a][b] = graph[b][a] = d;
        }
        for (i=0; i<cross; i++)
        {
            cin>>a;
            cityLocation[a] = i;
            cin>>name;
            strcpy(city[i],name);
        }

        memcpy(path,graph,sizeof(graph));
        for (k=0; k<n; k++)  //Floyd
            for (i=0; i<n; i++)
                if (path[i][k] > ZERO)
                    for (j=0; j<n; j++)
                        if (path[k][j] > ZERO && i!=j)
        {
            d = path[i][k] + path[k][j];
            if (path[i][j] < ZERO || path[i][j] > d)
                path[i][j] = d;
        }
        for (i=0; i<n; i++)
            path[i][i] = 0;
        memset(shortPath,255,sizeof(shortPath));
        for (i=0; i<n; i++) //求路口到城市最短路上的第一个路口
            for (j=0; j<n; j++)
                if (cityLocation[j] >= 0)
                    for (k=0; k<n; k++)
                        if (graph[i][k] >= ZERO/*路口 i 和路口 k 之间有一条边*/ && fabs(path[i][j]-path[k][j]-graph[i][k])<ZERO)
        {
            shortPath[i][j] = k;
            break;
        }
 
        if (iCase != 1)
            cout<<endl;
        int listNum;
        int signNum;
        scanf("%d",&signNum);
        for (i=0; i<signNum; i++)
        {
            cin>>a>>b>>d;
            if (i != 0)
                cout<<endl;
            listNum = -1;
            for (j=0; j<n; j++)
                if (cityLocation[j] >= 0 && shortPath[a][j] == b)
            {
                signList[++listNum].cityName = cityLocation[j];
                signList[listNum].distance = int(path[a][j]-d+ZERO+0.5);
            }
            qsort(signList,listNum+1,sizeof(sign),&cmp);
            for (j=0; j<=listNum; j++)
            {
                printf("%-20s",city[signList[j].cityName]);
                printf("%d\n",signList[j].distance);
            }
        }
    }

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值