更新了27题,还剩5题
00x
L2-001 紧急救援 (25 分)
复杂了一些的最短路,用优先队列对查找最小 dis
的过程做了优化。dis[i]
表示起点到 i
的最短路长度,pre[i]
表示 i
的前驱,cnt[i]
表示到达 i
的最短路条数,sum[i]
表示最多的救援队数目。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 505
using namespace std;
int n, m, s, d, x, y, z;
int num[N], path[N][N], dis[N], pre[N], cnt[N], sum[N];
bool vis[N];
struct Node {
int key, value;
Node(int k, int v) {
key = k;
value = v;
}
bool operator<(const Node &a) const {
return value > a.value; }
};
void dijkstra() {
pre[s] = -1;
cnt[s] = 1;
sum[s] = num[s];
dis[s] = 0;
priority_queue<Node> q;
q.push(Node(s, 0));
while (!q.empty()) {
int k = q.top().key;
q.pop();
if (vis[k]) continue;
vis[k] = true;
for (int i = 0; i < n; ++i) {
if (!vis[i]) {
int cur_dis = dis[k] + path[k][i];
int cur_sum = sum[k] + num[i];
if (cur_dis < dis[i]) {
dis[i] = cur_dis;
pre[i] = k;
cnt[i] = cnt[k];
sum[i] = cur_sum;
} else if (cur_dis == dis[i]) {
cnt[i] += cnt[k];
if (cur_sum > sum[i]) {
sum[i] = cur_sum;
pre[i] = k;
}
}
q.push(Node(i, dis[i]));
}
}
}
printf("%d %d\n", cnt[d], sum[d]);
stack<int> stk;
int k = d;
while (k != -1) {
stk.push(k);
k = pre[k];
}
printf("%d", stk.top());
stk.pop();
while (!stk.empty()) {
printf(" %d", stk.top());
stk.pop();
}
printf("\n");
}
int main() {
memset(path, INF, sizeof(path));
memset(dis, INF, sizeof(dis));
scanf("%d%d%d%d", &n, &m, &s, &d);
for (int i = 0; i < n; ++i) scanf("%d", &num[i]);
for (int i = 0; i < m; ++i) {
scanf("%d%d%d", &x, &y, &z);
path[x][y] = path[y][x] = z;
}
dijkstra();
return 0;
}
L2-002 链表去重 (25 分)
典型的空间换时间,如果按照是否重复然后一个一个删除重复的,肯定会超时。vis
数组做标记,没重复就放到第一个队列里,重复的放到第二个队列里,最后读一遍两个队列就好,复杂度差不多是 O(n)
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data, next;
};
int head, n, a, b, c;
vector<Node> node(100005);
vector<bool> vis(10005);
queue<int> q1, q2;
int main() {
scanf("%d%d", &head, &n);
while (n--) {
scanf("%d%d%d", &a, &b, &c);
node[a].data = b;
node[a].next = c;
}
for (int i = head; i != -1; i = node[i].next) {
if (!vis[abs(node[i].data)]) {
vis[abs(node[i].data)] = true;
q1.push(i);
} else
q2.push(i);
}
int pos = q1.front();
q1.pop();
printf("%05d %d ", pos, node[pos].data);
while (!q1.empty()) {
pos = q1.front();
q1.pop();
printf("%05d\n%05d %d ", pos, pos, node[pos].data);
}
printf("-1\n");
if (!q2.empty()) {
pos = q2.front();
q2.pop();
printf("%05d %d ", pos, node[pos].data);
while (!q2.empty()) {
pos = q2.front();
q2.pop();
printf("%05d\n%05d %d ", pos, pos, node[pos].data);
}
printf("-1");
}
return 0;
}
L2-003 月饼 (25 分)
基本的结构体排序加贪心,但是这个 C++
里的小数真是奇怪啊,不知道精度发生了什么神奇的错误,下面第一个代码提交一直有一组数据过不了,把 int
换成 double
就对了???。。。??
#include <bits/stdc++.h>
using namespace std;
struct Node {
int x, y;
double z;
bool operator<(const Node &node) const {
return z > node.z; }
} a[1005];
int n, d;
int main() {
cin >> n >> d;
for (int i = 0; i < n; ++i) cin >> a[i].x;
for (int i = 0; i < n; ++i) {
cin >> a[i].y;
a[i].z = a[i].y * 1.0 / a[i].x;
}
sort(a, a + n);
double sum = 0;
for (int i = 0; i < n; ++i) {
if (d >= a[i].x) {
d -= a[i].x;
sum += a[i].y;
} else {
sum += d * a[i].z;
break;
}
}
cout << fixed << setprecision(2) << sum;
return 0;
}
正确代码,太坑了吧:
#include <bits/stdc++.h>
using namespace std;
struct Node {
double x, y, z; // x, y 换成 double
bool operator<(const Node &node) const {
return z > node.z; }
} a[1005];
int n;
double d; // d 换成 double
int main() {
cin >> n >> d;
for (int i = 0; i < n; ++i) cin >> a[i].x;
for (int i = 0; i < n; ++i) {
cin >> a[i].y;
a[i].z = a[i].y / a[i].x;
}
sort(a, a + n);
double sum = 0;
for (int i = 0; i < n; ++i) {
if (d >= a[i].x) {
d -= a[i].x;
sum += a[i].y;
} else {
sum += d * a[i].z;
break;
}
}
cout << fixed << setprecision(2) << sum;
return 0;
}
L2-004 这是二叉搜索树吗? (25 分)
本以为上完数据结构的课应该就会各种树了,结果发现自己还是太年轻。这题按照二叉搜索树的性质建树,先试试是不是二叉搜索树,再试试是不是二叉搜索树的 “镜像”,如果最后能建成就顺便输出后序遍历。
#include <bits/stdc++.h>
using namespace std;
int n, pre[1005], post[1005], cnt = 0;
bool flag;
void build(int l, int r) {
if (l > r) return;
int i = l + 1, j = r;
if (!flag) {
while (i <= r && pre[i] < pre[l]) ++i;
while (l < j && pre[j] >= pre[l]) --j;
} else {
while (i <= r && pre[i] >= pre[l]) ++i;
while (l < j && pre[j] < pre[l]) --j;
}
if (i - j != 1) return;
build(l + 1, j);
build(i, r);
post[cnt++] = pre[l];
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%d", &pre[i]);
build(0, n - 1);
if (cnt != n) {
flag = true;
cnt = 0;
build(0, n - 1);
}
if (cnt != n)
printf("NO\n");
else {
printf("YES\n");
printf("%d", post[0]);
for (int i = 1; i < cnt; ++i) printf(" %d", post[i]);
printf("\n");
}
return 0;
}
L2-008 最长对称子串 (25 分)
马拉车算法模板题,c(center)表示中间点,r(right)表示回文串的右边界。具体算法思路不说了,还有需要理解的就是 r 关于 c 的对称点为 2 * c - i
。
#include <bits/stdc++.h>
using namespace std;
int manacher(string s) {
string str = "$#";
for (int i = 0; i < s.size(); ++i) {
str.push_back(s[i]);