(学英语学算法)PAT甲级--All Roads Lead to Rome


我的个人小站: acking-you.github.io

题目


OJ平台

题目翻译

首先看这题目就知道:条条大路通罗马

单词积累

Indeed  事实上、的确
routes 路线
recommended 备受推崇的
# 例句
Indeed there are many different tourist routes from our city to Rome.
# 翻译
事实上从我们的城市到罗马有很多条不同的路线。

题目描述

原文
Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.

翻译
事实上从我们的城市到罗马有很多条不同的路线。你应该为你的客人找到花费最少且得到最大幸福值的路线。

输入描述

原文
For each case, the first line contains 2 positive integers N (2<=N<=200), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N-1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format “City1 City2 Cost”. Here the name of a city is a string of 3 capital English letters, and the destination is always ROM which represents Rome.

翻译
对每个测试用例而言,第一行包含两个正整数:
N,代表城市的数量。K,代表任意两个城市之间道路的总数量。
Starting city,代表开始所在的城市。接下来 N-1 行,每行给定城市的名字和到达这个城市能获得的幸福值(最开始的城市没有幸福值)。
接下来K行,每行用于描述一条两个城市之间的道路,以"city1 city2 cost"格式进行描述,表示两个城市的名字,以及他们之间的道路需要的cost。这里的城市名字都是用是哪个长度的英文单词表示,ROM代表罗马这个城市。

输出描述

原文
you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommended route. Then in the next line, you are supposed to print the route in the format “City1->City2->…->ROM”.
翻译
第一行你必须打印四个数字:1. 最小花费的不同路线数量,2. 对应的最小花费,3. 对应的最大happiness,4. 平均happiness。
第二行打印行走路线。

解题分析

这个题目和之前PAT的这题: Emergency 的处理方式一模一样。都是计算边权的个数以及保证最小边权的同时点权的最大值。需要的特殊处理的部分就是,它并不是直接输入的编号,而是通过字符串的方式进行城市的描述,所以我们写Dijkstra算法之前先把字符串与数字进行映射,这样之后就是正常的Dijkstra算法了,最后通过path进行路径打印即可。

解题代码详解

题目所需要的参数

//输入需要的数据
int N,K;
string start;
unordered_map<string,int>check1;
const char* check2[MaxN];
int points[MaxN];

//更新答案需要的数据
int nums[MaxN];//记录到达某个结点最短路径有多少条
int w[MaxN];//记录最短路径中点权的最大值

//Dij算法需要的参数
int path[MaxN];
int dist[MaxN];
bitset<MaxN> visit;

Input模块

void Input(){
    ios::sync_with_stdio(false);
    memset(head,0xff,sizeof(head));
    memset(dist,0x3f,sizeof(dist));
    cin>>N>>K>>start;
    check2[0] = start.c_str();
    for(int i=1;i<N;i++){
        string* x = new string; //一定要用堆内存,不然一旦这个范围一结束,内存将会自动销毁,则check2指针指向的内存无数据
        int point;
        cin>>(*x)>>point;
        check2[i] = x->c_str();
        points[i] = point;
        check1[(*x)] = i;
    }
    for (int i = 0; i < K; ++i){
        string x,y;int len;cin>>x>>y>>len;
        int a = check1[x],b = check1[y];
        add(a,b,len);
        add(b,a,len);
    }
}

链式前向星建图

//建图需要的数据和操作
int tot = 0;
int head[MaxN];
struct{
    int to;
    int len;
    int next;
}edge[MaxN*MaxN];
void add(int a,int b,int len){
    edge[tot].to =  b;
    edge[tot].len = len;
    edge[tot].next = head[a];
    head[a] = tot++;
}

Dij算法的操作

//Dij操作
int findMin() {
    int minV = 0;
    int cmp = INF;
    for (int i = 1; i < N; i++) {
        if (!visit[i] && dist[i] < cmp) {
            cmp = dist[i];
            minV = i;
        }
    }
    visit[minV] = 1;
    return minV;
}
void Dij() {
    for (int i = 0; i < N; i++) {
        int node = findMin();
        if (node == 0)
            break;
        for (int i = head[node]; i != -1; i = edge[i].next) {
            if (!visit[edge[i].to]) {
                if (dist[edge[i].to] > edge[i].len + dist[node]) {
                    dist[edge[i].to] = edge[i].len + dist[node];
                    path[edge[i].to] = node;
                    nums[edge[i].to] = nums[node];
                    w[edge[i].to] = w[node] + points[edge[i].to];
                } else if (dist[edge[i].to] == edge[i].len + dist[node]) {
                    nums[edge[i].to] += nums[node];
                    if (w[edge[i].to] < w[node] + points[edge[i].to]) {
                        w[edge[i].to] = w[node] + points[edge[i].to];
                        path[edge[i].to] = node;
                    }
                }
            }
        }
    }
}

print操作

// 打印操作,用栈实现LIFO
void print() {
    vector<int>St;
    string end = "ROM";
    int ed = check1[end];
    int cnt = 1;
    int next = path[ed];
    while (next) {
        St.push_back(next);
        cnt++;
        next = path[next];
    }

    int happiness = w[ed];
    int average = happiness / cnt;
    cout << nums[ed] << ' ' << dist[ed] << ' ' << happiness << ' ' << average << '\n';
    cout << start;

    while (!St.empty()) {
        cout << "->" << check2[St.back()];
        St.pop_back();
    }
    cout << "->" << end;
}

整合代码得到答案

效率还行

我的答案:

#include<bits/stdc++.h>
using namespace std;
#define MaxN 202
#define INF 0x3f3f3f3f
//输入需要的数据
int N, K;
string start;
unordered_map<string, int>check1;
const char* check2[MaxN];
int points[MaxN];

//更新答案需要的数据
int nums[MaxN];//记录到达某个结点最短路径有多少条
int w[MaxN];//记录最短路径中点权的最大值

//Dij算法需要的参数
int path[MaxN];
int dist[MaxN];
bitset<MaxN> visit;

//建图需要的数据
int tot = 0;
int head[MaxN];
struct {
    int to;
    int len;
    int next;
} edge[MaxN * MaxN];
void add(int a, int b, int len) {
    edge[tot].to =  b;
    edge[tot].len = len;
    edge[tot].next = head[a];
    head[a] = tot++;
}
void Input() {
    ios::sync_with_stdio(false);
    memset(head, 0xff, sizeof(head));
    memset(dist, 0x3f, sizeof(dist));
    cin >> N >> K >> start;
    check2[0] = start.c_str();
    for (int i = 1; i < N; i++) {
        string* x = new string; //一定要用堆内存,不然一旦这个范围一结束,内存将会自动销毁,则check2指针指向的内存无数据
        int point;
        cin >> (*x) >> point;
        check2[i] = x->c_str();
        points[i] = point;
        check1[(*x)] = i;
    }
    for (int i = 0; i < K; ++i) {
        string x, y; int len; cin >> x >> y >> len;
        int a = check1[x], b = check1[y];
        add(a, b, len);
        add(b, a, len);
    }
}

//Dij操作
int findMin() {
    int minV = 0;
    int cmp = INF;
    for (int i = 1; i < N; i++) {
        if (!visit[i] && dist[i] < cmp) {
            cmp = dist[i];
            minV = i;
        }
    }
    visit[minV] = 1;
    return minV;
}
void Dij() {
    for (int i = 0; i < N; i++) {
        int node = findMin();
        if (node == 0)
            break;
        for (int i = head[node]; i != -1; i = edge[i].next) {
            if (!visit[edge[i].to]) {
                if (dist[edge[i].to] > edge[i].len + dist[node]) {
                    dist[edge[i].to] = edge[i].len + dist[node];
                    path[edge[i].to] = node;
                    nums[edge[i].to] = nums[node];
                    w[edge[i].to] = w[node] + points[edge[i].to];
                } else if (dist[edge[i].to] == edge[i].len + dist[node]) {
                    nums[edge[i].to] += nums[node];
                    if (w[edge[i].to] < w[node] + points[edge[i].to]) {
                        w[edge[i].to] = w[node] + points[edge[i].to];
                        path[edge[i].to] = node;
                    }
                }
            }
        }
    }
}


// 打印操作,用栈实现LIFO
void print() {
    vector<int>St;
    string end = "ROM";
    int ed = check1[end];
    int cnt = 1;
    int next = path[ed];
    while (next) {
        St.push_back(next);
        cnt++;
        next = path[next];
    }

    int happiness = w[ed];
    int average = happiness / cnt;
    cout << nums[ed] << ' ' << dist[ed] << ' ' << happiness << ' ' << average << '\n';
    cout << start;

    while (!St.empty()) {
        cout << "->" << check2[St.back()];
        St.pop_back();
    }
    cout << "->" << end;
}

int main() {
    Input();
    //第一次Dij处理
    dist[0] = 0;
    nums[0] = 1;
    for (int i = head[0]; i != -1; i = edge[i].next) {
        dist[edge[i].to] = edge[i].len;
        w[edge[i].to] = points[edge[i].to];
        nums[edge[i].to] = nums[0];
    }
    Dij();
    print();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值