📜  C++ 中的 Patrick 和 Shopping codeforces(1)

📅  最后修改于: 2023-12-03 14:39:54.515000             🧑  作者: Mango

C++ 中的 Patrick 和 Shopping codeforces

本篇介绍的是来自 Codeforces 的 Patrick 和 Shopping 题目,涉及到了 C++ 语言的基础知识和算法。

Patrick

题目描述:给出一个字符串 $s$ 和一个字符 $c$,对于 $s$ 中的每个位置,求它到离它最近的 $c$ 的距离。

解题思路:首先,我们可以循环字符串 $s$,用一个变量 $pos$ 记录上一个字符 $c$ 出现的位置,那么当前位置到最近的 $c$ 的距离就是 $i - pos$ 和 $pos - i$ 中的较小值。代码如下:

string s;
char c;
cin >> s >> c;
int pos = -1;
vector<int> ans;
for(int i = 0; i < s.length(); i++){
    if(s[i] == c) pos = i;
    if(pos == -1) ans.push_back(INT_MAX);
    else ans.push_back(min(i - pos, pos - i));
}

注意,这里用了一个 INT_MAX 来表示当前位置到最近的 $c$ 的距离的初始值,这是因为在当前位置之前没有出现过 $c$,所以它的距离是无限大,即不可到达。为了输出美观,我们可以把 vector 中的结果转换为 string 输出。

string res;
for(int i = 0; i < ans.size(); i++){
    res += to_string(ans[i]) + " ";
}
cout << res << endl;

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

int main(){
    string s;
    char c;
    cin >> s >> c;
    int pos = -1;
    vector<int> ans;
    for(int i = 0; i < s.length(); i++){
        if(s[i] == c) pos = i;
        if(pos == -1) ans.push_back(INT_MAX);
        else ans.push_back(min(i - pos, pos - i));
    }
    string res;
    for(int i = 0; i < ans.size(); i++){
        res += to_string(ans[i]) + " ";
    }
    cout << res << endl;
    return 0;
}
Shopping

题目描述:有 $n$ 个商店,第 $i$ 个商店卖第 $i$ 种商品,第 $i$ 种商品的价格为 $a_i$。Patrick 从商店 $x$ 出发,需要买齐 $n$ 种商品,买完后回到商店 $x$。每次到另一个商店需要花费 $t$ 的时间,每次将某个商品搬运回商店 $x$ 需要花费 $s$ 的时间。求 Patrick 购买所有商品和回到商店 $x$ 的最少时间。

解题思路:这是一道经典的旅行商问题(TSP)变形。我们可以使用状态压缩加动态规划来解决这个问题。首先,我们定义 $dp_{i,S}$ 表示 Patrick 从 $x$ 出发,已经购买了集合 $S$ 中的商品,且当前在商店 $i$ 的最短时间。其中,$S$ 是一个二进制状态码,$S$ 的第 $i$ 位表示第 $i$ 种商品是否已购买,如 $S=3$ 时,表示 Patrick 已经购买了第 1 种和第 2 种商品。

对于 $dp_{i,S}$,我们可以枚举上一个购买的商品 $j$,根据题目要求,将状态转移为 $dp_{i,S}=\min(dp_{j,S\setminus{j}}+t_{i,j}+s_i)$。其中,$t_{i,j}$ 表示从商店 $i$ 到商店 $j$ 的时间,$s_i$ 表示将第 $i$ 种商品搬运回商店 $x$ 的时间,$S\setminus{j}$ 表示去除状态 $S$ 中的第 $j$ 位。这里的 $s_i$ 是一个定值,因为我们已经知道了所有商品的价格 $a_i$,所以可以先求出每个商品在商店 $x$ 的价格总和 $sum$,那么购买其他商品和将第 $i$ 种商品搬运回商店 $x$ 的价格总和就是 $sum-a_i$。

初始状态为 $dp_{x,{x}}=0$,其他状态为 $dp_{i,S}=+\infty$。最终答案即为 $\min(dp_{x,S}+t_{i,x})$,其中 $S$ 包含了所有商品。

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

const int N = 20, INF = 0x3f3f3f3f;

int n, x;
int a[N], sum[N], t[N][N], s[N];
int dp[1 << N][N];

int main(){
    scanf("%d%d", &n, &x);
    x--;
    for(int i = 0; i < n; i++){
        scanf("%d", a + i);
        sum[0] += a[i];
    }
    for(int i = 1; i < n; i++) sum[i] = sum[i - 1] - a[i - 1];
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++) scanf("%d", &t[i][j]);
    for(int i = 0; i < n; i++) scanf("%d", s + i);

    memset(dp, INF, sizeof dp);
    dp[1 << x][x] = 0;
    for(int S = 1; S < (1 << n); S++){
        for(int i = 0; i < n; i++){
            if(dp[S][i] == INF) continue;
            for(int j = 0; j < n; j++){
                if(S >> j & 1) continue;
                dp[S | 1 << j][j] = min(dp[S | 1 << j][j], dp[S][i] + t[i][j] + s[j] + (S == (1 << n) - 1 ? t[j][x] + sum[j] : 0));
            }
        }
    }
    int ans = INF;
    for(int i = 0; i < n; i++){
        ans = min(ans, dp[(1 << n) - 1][i] + t[i][x]);
    }
    printf("%d\n", ans);

    return 0;
}

以上两道题目涉及到的 C++ 基础知识和算法都是比较基础的,是每个 C++ 初学者必须掌握的知识点。通过练习以上两道题目,相信你在 C++ 中的编程能力和算法能力都能得到提升。