【題解】牛客程式設計巔峰賽S1賽季第1場 - 青銅&白銀局
阿新 • • 發佈:2020-07-10
總結
- 沒寫過函數語言程式設計,十分不習慣
- \(\texttt{C}\)題的\(\texttt{vector}\)不會用,像傻子一樣看著螢幕不知道該咋辦
- 罰時罰了五次,還都是傻逼錯誤
最後成了一個小小的白銀……我真是太菜了!
題解
A 移動字母
題意
給出一個字串,讓你把這個字串中的小寫字母\(a\)移到字串的最後
思路
眾所周知\(\texttt{string}\)是具有可加性的,所以可以新建一個字串\(t\)儲存新的字串,並用\(cnt\)記錄\(a\)的個數,將\(s\)迴圈一遍如果\(s[i]=='a'\)就累積到計數器\(cnt\)中,否則加入\(t\)串中,然後迴圈一遍將\(cnt\)
程式碼
class Solution { public: string change(string s) { // write code here int n = s.length(); int cnt = 0; string t; for (int i = 0; i < n; i++) if (s[i] == 'a') cnt++; else t += s[i]; for (int i = 1; i <= cnt; i++) t += 'a'; return t; } };
B 魔法數字
題意
給出兩個數\(n,m\),有三種操作:
- 當前數加\(1\)
- 當前數\(-1\)
- 當前數平方
問\(n\)最少操作多少次可以變成\(m\)
思路
廣搜
用一個\(pair\)型的佇列,第一維是當前數,第二維是所用的步數
根據題目條件設定三個變數分別為加之後的結果、減之後的結果、平方之後的結果,按照常規廣搜思路入佇列,根據廣搜的性質,最先搜到\(m\)的次數就是答案,返回即可
程式碼
class Solution { public: int solve(int n, int m) { queue <pair<int, int> > Q; int vis[10001], x, y; memset(vis, 0, sizeof(vis)); Q.push({n, 0}), vis[n] = 1; while (Q.size()) { x = Q.front().first, y = Q.front().second; Q.pop(); if (x == m) return y; //a加之後的結果,b減之後的結果,c平方之後的結果 int a = x + 1, b = x - 1, c = x * x; if (a < 1000 && !vis[a]) Q.push({a, y + 1}), vis[a] = 1; if (b >= 0 && !vis[b]) Q.push({b, y + 1}), vis[b] = 1; if (c < 1000000 && !vis[c]) Q.push({c, y + 1}), vis[c] = 1; } } };
C 牛妹的春遊
題意
給出需要的麵包數\(n\)和飲料數\(m\)
給出\(?\)個揹包,每個揹包中有\(p_1\)個麵包,\(p_2\)瓶飲料,花費為\(p_3\)
求最小花費
思路
二維費用揹包問題
比賽的時候不會用\(\texttt{vector}\)。。。。結束之後發現和陣列沒啥兩樣
在題解裡看到一個大佬說函式引數是可以改名的……於是改成了\(a,b,v\)
其實揹包的數量就是\(v.size()\)
然後就和\(01\)揹包類似了,選或不選這個揹包,優化也一樣
但是其實是可以買多的,可能會出現減出負數的情況,這個時候只要對負數體積取\(0\)即可,表示即使當前需要的飲料/麵包小於袋子中的飲料/麵包數量依然可以購買
最後返回\(f[a][b]\)即可
程式碼
class Solution {
public:
int f[2000][2000];
int minCost(int a, int b, vector<vector<int> >& v) {
memset(f, 0x3f, sizeof(f));
f[0][0] = 0;
for (int i = 0; i < v.size(); i++)
for (int j = a; j >= 0; j--)
for (int k = b; k >= 0; k--)
f[j][k] = min(f[j][k], f[max(j - v[i][0], 0)][max(k - v[i][1], 0)] + v[i][2]);
return f[a][b];
}
};