1、最大波动
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int n, last, res;
int main() {
cin >> n >> last;
for (int i = 1; i < n; i ++ ) {
int x; cin >> x;
res = max(res, abs(x - last));
last = x;
}
cout << res << endl;
return 0;
}
2、火车购票
#include <iostream>
#include <algorithm>
using namespace std;
int n, p;
int cnt[20], per[20][5];
int main() {
cin >> n;
while (n--) {
cin >> p;
bool flag = false;
for (int i = 0; i < 20; i++) {
if (5 - cnt[i] >= p) {
cnt[i] += p, flag = true;
for (int j = 0; j < 5; j++) {
if (!per[i][j]) {
per[i][j] = 1;
cout << i * 5 + j + 1 << " ";
p -- ;
}
if (!p) break;
}
break;
}
}
if (!flag)
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 5; j++) {
if (!per[i][j]) {
per[i][j] = 1;
cout << i * 5 + j + 1 << " ";
cnt[i]++;
p--;
}
if (!p) break;
}
if (!p) break;
}
cout << endl;
}
return 0;
}
3、炉石传说
数组 p [ 2 ] [ 10 ] p[2][10] p[2][10]:第一维 0 0 0 表示前者, 1 1 1 表示后者;第二维 0 0 0 表示英雄生命值, 1 ∼ 7 1 \sim 7 1∼7 分别表示随从的生命值.
#include <iostream>
#include <algorithm>
using namespace std;
struct Role {
int a, h; // 攻击力、生命值
} p[2][10];
void remove(int k, int pos) {
for (int i = pos; i <= 7; i++)
p[k][i] = p[k][i + 1];
}
int main() {
int n; cin >> n;
p[0][0].h = p[1][0].h = 30;
int k = 0;
while (n--) {
string op; cin >> op;
if (op == "end") k ^= 1; // 交换回合
else if (op == "summon") {
int pos, a, h; cin >> pos >> a >> h;
for (int i = 7; i > pos; i--) p[k][i] = p[k][i - 1];
p[k][pos] = {a, h};
} else {
int a, d; cin >> a >> d;
p[k][a].h -= p[!k][d].a;
p[!k][d].h -= p[k][a].a;
if (a && p[k][a].h <= 0) remove(k, a);
if (d && p[!k][d].h <= 0) remove(!k, d);
}
}
if (p[0][0].h <= 0) puts("-1");
else if (p[1][0].h <= 0) puts("1");
else puts("0");
for (int k = 0; k < 2; k++) {
cout << p[k][0].h << endl;
int s = 0;
for (int i = 1; i <= 7; i++)
if (p[k][i].h > 0) s++;
cout << s << ' ';
for (int i = 1; i <= s; i++)
cout << p[k][i].h << ' ';
cout << endl;
}
return 0;
}
4、交通规划 (最短路树)
首先应该明确,最终选择出来的权值之和最小的边构成的一定是一棵树而不是环。如果存在一个环,环上存在从
A
→
C
A \rightarrow C
A→C 与
B
→
C
B \rightarrow C
B→C 两条最短路径,并且从
B
→
C
B \rightarrow C
B→C 的路径权值大于
0
0
0 。那么现在将
B
→
C
B \rightarrow C
B→C 之间的路径删除后,依然是满足最短路径的,所以最终选择出来的一定是一棵树。

但是这个题目并不是求解最小生成树,比如存在如下的图, 如果求解最小生成树后,从
A
→
C
A \rightarrow C
A→C 的最小距离就从
3
3
3 变成了
4
4
4。

这个题目是求解最短路树。求解方法:
假设有点 a 、 b a、b a、b 到根结点 1 1 1 的距离分别为 d i s t [ a ] 、 d i s t [ b ] dist[a]、dist[b] dist[a]、dist[b],且 a 、 b a、b a、b 之间边的权值为 w a b w_{ab} wab,如果要选择 a b ab ab 这条边,就必须要满足式子 d i s t [ a ] = d i s t [ b ] + w a b dist[a] = dist[b] + w_{ab} dist[a]=dist[b]+wab因此可以先预处理对于每一个点有哪些边可以选择,然后由题目所有边的权值 1 ≤ c ≤ 1000 1\le c \le1000 1≤c≤1000,可以知道所有满足上式的边一定也满足 d i s t [ a ] > d i s t [ b ] dist[a] > dist[b] dist[a]>dist[b],因此可见最佳方案会是一个拓扑图。
如果采用拓扑顺序来考虑所有的点,当枚举到第 i i i 个点的时候,用 f [ i ] f[i] f[i] 表示选择前 i i i 点的最小权值之和,并且假设在前 i − 1 i - 1 i−1 个点中存在指向第 i i i 个结点的边: j → i 、 k → i 、 t → i j \rightarrow i、k \rightarrow i、t \rightarrow i j→i、k→i、t→i,那么就有 f ( i ) = f ( i − 1 ) + m i n { w j i , w k i , w t i } f(i) = f(i-1) + min\{ w_{ji},w_{ki},w_{ti} \} f(i)=f(i−1)+min{wji,wki,wti}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010, M = 200010, INF = 0x3f3f3f3f;
int n, m;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], q[N];
bool st[N];
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void spfa() {
memset(dist, 0x3f, sizeof dist); dist[1] = 0;
int hh = 0, tt = 1; q[0] = 1;
while (hh != tt) {
int t = q[hh++];
if (hh == N) hh = 0;
st[t] = false;
for (int i = h[t]; ~i; i = ne[i]) {
int j = e[i];
if (dist[j] > dist[t] + w[i]) {
dist[j] = dist[t] + w[i];
if (!st[j]) {
q[tt++] = j;
if (tt == N) tt = 0;
st[j] = true;
}
}
}
}
}
int main() {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while (m--) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
spfa();
int res = 0;
for (int a = 2; a <= n; a++) {
int minw = INF;
for (int j = h[a]; ~j; j = ne[j]) {
int b = e[j];
if (dist[a] == dist[b] + w[j])
minw = min(minw, w[j]);
}
res += minw;
}
printf("%d\n", res);
return 0;
}

被折叠的 条评论
为什么被折叠?



