题目链接:https://www.nowcoder.com/test/10714908/summary。
做了这套题,感受就是数据有点弱(第三题和第四题的数据弱,错误的算法也能过,建议牛客网加强数据)。题倒是很常规,考察了最短路算法,背包问题,贪心,字符串模拟和找规律。
第一题:牛牛取快递
题目
牛牛的快递到了,他迫不及待地想去取快递,但是天气太热了,以至于牛牛不想在烈日下多走一步。他找来了你,请你帮他规划一下,他最少要走多少距离才能取回快递。
输入描述
每个输入包含一个测试用例。
输入的第一行包括四个正整数,表示位置个数N
(2<=N<=10000)(2<=N<=10000),道路条数M
(1<=M<=100000)(1<=M<=100000),起点位置编号S
(1<=S<=N)(1<=S<=N)和快递位置编号T
(1<=T<=N)(1<=T<=N)。位置编号从1
到N
,道路是单向的。数据保证S≠T
,保证至少存在一个方案可以从起点位置出发到达快递位置再返回起点位置。
接下来M
行,每行包含三个正整数,表示当前道路的起始位置的编号U
(1<=U<=N)(1<=U<=N),当前道路通往的位置的编号V
(1<=V<=N)(1<=V<=N) 和当前道路的距离D
(1<=D<=1000)(1<=D<=1000)。
输出描述
对于每个用例,在单独的一行中输出从起点出发抵达快递位置再返回起点的最短距离。
样例
in:
3 3 1 3
1 2 3
2 3 3
3 1 1
out:
7
解析: 最短路模板,用的是Dijkstra队列优化
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 10000 + 10;
int n, m, st, ed;
struct edge {
int v;
int d;
};
vector<edge> Edge[maxn];
struct Node {
int v;
int d;
bool operator<(const Node &a)const{
return d > a.d;
}
};
int d[maxn], vis[maxn], pre[maxn];
int Dijkstra(int st, int ed) {
memset(d, INF, sizeof(d));
memset(vis, 0, sizeof(vis));
d[st] = 0;
priority_queue<Node> q;
q.push(Node{st, d[st]});
while (!q.empty()) {
Node f = q.top(); q.pop();
int u = f.v;
if (vis[u] == 1) continue;
vis[u] = 1;
for (int i = 0; i < Edge[u].size(); i++) {
int v = Edge[u][i].v;
if (vis[v] == 1) continue;
if (d[v] > d[u] + Edge[u][i].d) {
d[v] = d[u] + Edge[u][i].d;
pre[v] = u;
q.push(Node{v, d[v]});
}
}
}
return d[ed];
}
int main() {
cin >> n >> m >> st >> ed;
for (int i = 0; i < m; i++) {
int a, b, c;
cin >> a >> b >> c;
Edge[a].push_back(edge{b, c});
}
int dis1 = Dijkstra(st, ed);
int dis2 = Dijkstra(ed, st);
printf("%d\n", dis1+dis2);
return 0;
}
第二题:牛牛炒股票
题目
牛牛得知了一些股票今天买入的价格和明天卖出的价格,他找犇犇老师借了一笔钱,现在他想知道他最多能赚多少钱。
输入描述
每个输入包含一个测试用例。
输入的第一行包括两个正整数,表示股票的种数N
(1<=N<=1000)(1<=N<=1000)和牛牛借的钱数M
(1<=M<=1000)(1<=M<=1000)。
接下来N
行,每行包含两个正整数,表示这只股票每一股的买入价X
(1<=X<=1000)(1<=X<=1000) 和卖出价Y
(1<=Y<=2000)(1<=Y<=2000)。
每只股票可以买入多股,但必须是整数。
输出描述
输出一个整数表示牛牛最多能赚的钱数。
样例
in:
3 5
3 6
2 3
1 1
out:
4
解析:完全背包模板,然后每个物品的价值是卖出价减去买入价
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 10;
int w[maxn], v[maxn];//w是体积,v是价值
int dp[maxn];
void init() {
memset(w, 0, sizeof(w));
memset(v, 0, sizeof(v));
memset(dp, 0, sizeof(dp));
}
int n, m;
int main() {
init();
cin >> n >> m;
for (int i = 0; i < n; i++) {
int a, b;
cin >> a >> b;
w[i] = a;
v[i] = b - a;
}
dp[0] = 0;
for (int i = 0; i < n; i++) {
for (int j = w[i]; j <= m; j++) {
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
cout << dp[m] << endl;
return 0;
}
第三题:独立的牛牛
题目
小牛牛为了向他的父母表现他已经长大独立了,他决定搬出去自己居住一段时间。
一个人生活增加了许多花费: 牛牛每天必须吃一个水果并且需要每天支付x
元的房屋租金。
当前牛牛手中已经有f
个水果和d
元钱,牛牛也能去商店购买一些水果,商店每个水果售卖p
元。
牛牛为了表现他独立生活的能力,希望能独立生活的时间越长越好,牛牛希望你来帮他计算一下他最多能独立生活多少天。
输入描述
输入包括一行,四个整数
x, f, d, p
(1<=x,f,d,p<=2∗109)(1<=x,f,d,p<=2∗109),以空格分割
输出描述
输出一个整数, 表示牛牛最多能独立生活多少天。
样例
in:
3 5 100 10
out:
11
解析:这题比较简单,看代码吧;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll x, f, d, p;
int main() {
cin >> x >> f >> d >> p;
int k1 = min(f, d/x);
if (k1 < f) {
cout << k1 << endl;
return 0;
}
else {
int k2 = (d - x*f)/(p + x);
cout << (k1 + k2) << endl;
}
return 0;
}
第四题:牛牛吃雪糕
题目
最近天气太热了,牛牛每天都要吃雪糕。雪糕有一盒一份、一盒两份、一盒三份这三种包装,牛牛一天可以吃多盒雪糕,但是只能吃六份,吃多了就会肚子疼,吃少了就会中暑。而且贪吃的牛牛一旦打开一盒雪糕,就一定会把它吃完。请问牛牛能健康地度过这段高温期么?
输入描述
每个输入包含多个测试用例。
输入的第一行包括一个正整数,表示数据组数T
(1<=T<=100)(1<=T<=100)。
接下来N
行,每行包含四个正整数,表示高温期持续的天数N
(1<=N<=10000)(1<=N<=10000),一盒一份包装的雪糕数量A
(1<=A<=100000)(1<=A<=100000),一盒两份包装的雪糕数量B
(1<=B<=100000)(1<=B<=100000),一盒三份包装的雪糕数量C
(1<=A<=100000)(1<=A<=100000)。
输出描述
对于每个用例,在单独的一行中输出结果。如果牛牛可以健康地度过高温期则输出
"Yes"
,否则输出"No"
。
样例
in:
4
1 1 1 1
2 0 0 4
3 0 2 5
4 24 0 0
out:
Yes
Yes
No
Yes
解析:思路就是优先吃3份一盒的,然后2份一盒的,然后1份一盒的;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t, n, a, b, c;
//优先先吃3份一盒的,然后2份一盒的,然后1份一盒的;
int main() {
scanf("%d", &t);
while (t-- != 0) {
scanf("%d %d %d %d", &n, &a, &b, &c);
int k1 = c/2;
c %= 2;
if (k1 > 0) n -= k1;
int k2 = b/3;
b %= 3;
if (k2 > 0) n -= k2;
if (a >= 1 && b >= 1 && c == 1) {
a--;
b--;
c--;
n--;
}
if (a >= 2 && b == 2) {
b = 0;
a -= 2;
n--;
}
if (a >= 3 && c == 1) {
c = 0;
a -= 3;
n--;
}
if (a >= 4 && b == 1) {
b = 0;
a -= 4;
n--;
}
int k3 = a/6;
n -= k3;
a %= 6;
if (n > 0) printf("No\n");
else printf("Yes\n");
}
return 0;
}
第五题:牛牛打响指
题目
牛牛在地上捡到了一个手套,他带上手套发现眼前出现了很多个小人,当他打一下响指,这些小人的数量就会发生以下变化:如果小人原本的数量是偶数那么数量就会变成一半,如果小人原本的数量是奇数那么数量就会加一。现在牛牛想考考你,他要打多少次响指,才能让小人的数量变成1。
输入描述
每个输入包含一个测试用例。
输入的第一行包括一个正整数,表示一开始小人的数量N
(1<=N<=10100)(1<=N<=10100)。
输出描述
对于每个用例,在单独的一行中输出牛牛需要打多少次响指才能让小人的数量变成1。
样例
in:
10000
out:
20
解析:会Java的直接用Java大数BigInteger水过。
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int cnt = 0;
BigInteger n = in.nextBigInteger();
while (!n.equals(new BigInteger("1"))) {
BigInteger result = n.divide(new BigInteger("2"));
if (n.mod(new BigInteger("2")).equals(BigInteger.ZERO)) n = result;
else n = n.add(BigInteger.ONE);
cnt++;
}
System.out.println(cnt);
}
}