浙大 PAT 甲级 1072 Gas Station Dijkstra算法 单源最短路径

拈花ヽ惹草 提交于 2019-11-29 00:48:05

这题比较难,考察最短路径,加了很多复杂的条件。

第一步,读懂题意

首先题意需要读懂,候选加油站需要满足以下条件:

1、加油站离每个住宅的最短距离要在服务范围内;

2、针对每个候选加油站,求出这个加油站到每个住宅的最短距离,这些最短距离中最小的那一个值,也就是离整个住宅区的最短距离,越大越好;

3、如果有多个这样的候选加油站,那么针对每个候选加油站,求这个加油站到每个住宅的最短距离的和,最短距离和越小越好;

4、如果有多个这样的候选加油站,那么加油站的编号越小越好。

因此,解题思路是:

1、输入数据;

2、用Floyd算法求出两点之间的最短距离;

3、逐个判断哪个加油站是有效最优解;

4、按要求输出结果。

第二步,处理输入

输入有字符有数字,并且还有干扰输出,比如:

1、同一个起点和终点间有两条路,这时候只保存最短的那条;

2、起点和终点是同一个位置,忽略;

3、用字符数组接收编号,如果开头是G,那么为加油站,将它转换成数字N+i(N是住宅的总数,i是该加油站的数字编号)。

第三步,选择算法

大致有两种算法:

1、将问题看作全源最短路径,用Floyd算法求得每两点间的最短距离,从而找出最佳候选位置。

Floyd算法的时间复杂度大约是三次方,最后一个用例会超时。

2、改变思路,将问题看作单源最短路径,针对每个加油站都做一次单源最短路径,用Dijkstra算法,时间复杂度大约是二次方,而加油站候选位置不超过10个,因此仍然是二次方复杂度。问题解决。

最短路径算法是很重要的,通过这题可以再次回顾一下两种最短路径算法。网上的博客或多或少不够清晰、完整,还缺少证明的过程,不利于记忆学习。对于这些经典的算法,推荐阅读纸质书籍,比如《算法导论》第24/25章。

AC代码

#include<stdio.h>
#include<vector>
#include<queue>
#include<functional>
#include<iterator>
using namespace std;
struct E
{
    int next;
    int c;
};
vector<E> edge[1011];
bool mark[1011];
int dis[1011];

int main()
{
    int N, M, K, D;
    scanf("%d%d%d%d", &N, &M, &K, &D);
    char start[5], end[5];
    int from, to;
    int d;
    for (int i = 0; i < K; i++)
    {
        scanf("%s%s%d", start, end, &d);
        if (start[0] != 'G')
        {
            from = atoi(start);
        }
        else
        {
            from = N + atoi(&start[1]);
        }
        if (end[0] != 'G')
        {
            to = atoi(end);
        }
        else
        {
            to = N + atoi(&end[1]);
        }
        if (from == to)
        {
            continue;
        }
        bool flag = true;
        for (int j = 0; j < edge[from].size(); j++)
        {
            if (edge[from][j].next == to)
            {
                flag = false;
                if (d < edge[from][j].c)
                {
                    edge[from][j].c = d;
                }
                break;
            }
        }
        if (!flag)
        {
            continue;
        }
        E e;
        e.next = to;
        e.c = d;
        edge[from].push_back(e);
        e.next = from;
        edge[to].push_back(e);
    }
    int bestStation = -1;
    int bestSum = 1000000;
    int bestMin = 0;
    for (int i = N + 1; i <= M + N; i++)
    {
        for (int j = 1; j <= M + N; j++)
        {
            dis[j] = -1;
            mark[j] = false;
        }
        dis[i] = 0;
        mark[i] = true;
        int newP = i;
        for (int j = 1; j < M + N; j++)
        {
            for (int k = 0; k < edge[newP].size(); k++)
            {
                int t = edge[newP][k].next;
                int c = edge[newP][k].c;
                if (mark[t] == true)
                {
                    continue;
                }
                if (dis[t] == -1 || dis[t] > dis[newP] + c)
                {
                    dis[t] = dis[newP] + c;
                }
            }
            int min = 100000;
            for (int k = 1; k <= M + N; k++)
            {
                if (mark[k] == true || dis[k] == -1)
                {
                    continue;
                }
                if (dis[k] < min)
                {
                    min = dis[k];
                    newP = k;
                }
            }
            mark[newP] = true;
        }
        int min = 100000, sum = 0;
        bool flag = true;
        for (int j = 1; j <= N; j++)
        {
            if (dis[j] > D || dis[j] == -1)
            {
                flag = false;
                break;
            }
            sum += dis[j];
            if (dis[j] < min)
            {
                min = dis[j];
            }
        }
        if (flag && ((min > bestMin) || (min == bestMin && sum < bestSum)))
        {
            bestMin = min;
            bestStation = i;
            bestSum = sum;
        }
    }
    if (bestStation == -1)
    {
        printf("No Solution\n");
    }
    else
    {
        printf("G%d\n%.1f %.1f\n", bestStation - N, (float)bestMin, (float)bestSum / N);
    }
    return 0;
}

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!