提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 7.1 稀疏矩阵之差
- 7.2 二叉树最短路径长度
- 7.3 文字编辑
- 7.4 方案计数
7.1 稀疏矩阵之差
7-1 稀疏矩阵之差
分数 100
作者 谷方明
单位 吉林大学
矩阵A和B都是稀疏矩阵。请计算矩阵的差A-B.如果A、B不能计算差值,输出"Illegal!"
输入格式:
矩阵的输入采用三元组表示,先A后B。对每个矩阵:
第1行,3个整数N、M、t,用空格分隔,分别表示矩阵的行数、列数和非0数据项数,10≤N、M≤50000,t≤min(N,M).
第2至t+1行,每行3个整数r、c、v,用空格分隔,表示矩阵r行c列的位置是非0数据项v, v在32位有符号整型范围内。三元组默认按行列排序。
输出格式:
矩阵A-B,采用三元组表示,默认按行列排序,非零项也在32位有符号整型范围内。
输入样例:
在这里给出一组输入。例如:
10 10 3
2 2 2
5 5 5
10 10 20
10 10 2
2 2 1
6 6 6
输出样例:
在这里给出相应的输出。例如:
10 10 4
2 2 1
5 5 5
6 6 -6
10 10 20
代码长度限制
16 KB
时间限制
100 ms
内存限制
10 MB
思路:
1.将稀疏矩阵按行列顺序存储
先存入然后使用sort排序保证行列序
2.将两个稀疏矩阵相减
因为行列小的要先存入,我这里认为如果一个矩阵已经合并结束,也不退出循环,而是将它代表结点的值赋值0,行列复制为无穷
在计算时若出现相减等于0的val值应避免录入
余下思路在注释体现
参考代码:
#include <iostream>
#include <vector>
#include <algorithm>
typedef struct {
int row;//行
int col;//列
int val;
}Matrix;
bool com(Matrix a, Matrix b) {
if (a.row != b.row) { return a.row < b.row; }
else if (a.col != b.col) { return a.col < b.col; }
}
using namespace std;
vector<Matrix> ans;
int min(int m, int n) {
if (m > n) {
return n;
}
else {
return m;
}
}
bool Isalessb(Matrix A, Matrix B) {//a是否小于b?
if (A.row != B.row) { return A.row < B.row; }
if (A.col != B.col) { return A.col < B.col; }
return false;
}
bool Isaequalb(Matrix A, Matrix B) {//a是否等于b?
if (A.row == B.row && A.col == B.col) {
return true;
}
return false;
}
Matrix* newjuzhen(int M, int N, int t) {
int row = 0, col = 0, val = 0;
int countA = 0;
Matrix* A = new Matrix[min(M, N)];
for (int i = 0; i < t; i++) {
scanf("%d%d%d", &row, &col, &val);
A[i].col = col;
A[i].row = row;
A[i].val = val;
}
sort(A, A + t, com);
return A;
}
void jianjuzhen(Matrix* A, Matrix* B, int t, int t2) {
int i = 0, j = 0, k = 0;
Matrix cupa, cupb;//对AB每个项的两个临时节点 节点相减后存入容器ans
while (i != t || j != t2) {//ij全部到头才停止循环
if (i != t) {
cupa.row = A[i].row;
cupa.col = A[i].col;
cupa.val = A[i].val;
}
else {
cupa.row = 10000000;
cupa.col = 10000000;
cupa.val = 0;
}
if (j != t2) {
cupb.row = B[j].row;
cupb.col = B[j].col;
cupb.val = B[j].val;
}
else {
cupb.row = 10000000;
cupb.col = 10000000;
cupb.val = 0;
}
if (Isalessb(cupa, cupb)) {//行列小的先录入保证ans的顺序
ans.push_back(cupa);
i++;
}
else if (Isaequalb(cupa, cupb)) {//行列值相等时 ab的val相减进行计算
if (cupa.val - cupb.val != 0) {
Matrix cuppp;
ans.push_back(Matrix());
ans.back().val = cupa.val - cupb.val;
ans.back().row = cupa.row;
ans.back().col = cupa.col;
}
i++; j++;//val相减等于0的情况由三元组的性质就不录入 ij直接进一位
}
else {
cupb.val = -cupb.val;//没有a的干扰 b直接录入的情况 由于b是减数所以val录入-b.val
ans.push_back(cupb);
j++;
}
}
}
int main() {
int M = 0, N = 0, t = 0;
int M2 = 0, N2 = 0, t2 = 0;
scanf("%d%d%d", &M, &N, &t);
Matrix* A = newjuzhen(M, N, t);
scanf("%d%d%d", &M2, &N2, &t2);
if (M != M2 || N != N2) {
printf("Illegal!");
}
else {
Matrix* B = newjuzhen(M2, N2, t2);
jianjuzhen(A, B, t, t2);
printf("%d %d %d\n", M, N, ans.size());
for (int i = 0; i < ans.size(); i++) {
printf("%d %d %d", ans[i].row, ans[i].col, ans[i].val);
if (i < ans.size() - 1) {
printf("\n");
}
}
}
}
7-2 二叉树最短路径长度
给定一棵二叉树T,每个结点赋一个权值。计算从根结点到所有结点的最短路径长度。路径长度定义为:路径上的每个顶点的权值和。
输入格式:
第1行,1个整数n,表示二叉树T的结点数,结点编号1..n,1≤n≤20000。
第2行,n个整数,空格分隔,表示T的先根序列,序列中结点用编号表示。
第3行,n个整数,空格分隔,表示T的中根序列,序列中结点用编号表示。
第4行,n个整数Wi,空格分隔,表示T中结点的权值,-10000≤Wi≤10000,1≤i≤n。
输出格式:
1行,n个整数,表示根结点到其它所有结点的最短路径长度。
输入样例:
在这里给出一组输入。例如:
4
1 2 4 3
4 2 1 3
1 -1 2 3
输出样例:
在这里给出相应的输出。例如:
1 0 3 3
代码长度限制
16 KB
时间限制
1000 ms
内存限制
10 MB
思路:
先根序列中根序列建树比较难 然后dfs求最短路径
参考代码:
#include<stdio.h>
int first[20010];
int mid[20010];
int left[20010];
int right[20010];
int value[20010];
int cost[20010];
void buildt(int , int , int );
void dfs(int root) {
if (!root) return;
cost[root] += value[root];
cost[left[root]] += cost[root];
cost[right[root]] += cost[root];
dfs(left[root]);
dfs(right[root]);
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &first[i]);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &mid[i]);
}
buildt(1, 1, n);
for (int i = 1; i <= n; i++) {
scanf("%d", &value[i]);
}
for (int i = 1; i <= n; i++) {
cost[i] = 0;
}
int root = first[1];
dfs(root);
for (int i = 1; i < n; i++)
printf("%d ", cost[i]);
printf("%d", cost[n]);
}
void buildt(int d, int s2, int e2) {
int i = s2;
while (first[d] != mid[i]) {
i++;
}
if (s2 == e2) {
left[first[d]] = right[first[d]] = 0;
}
else if (i == e2) {
right[first[d]] = 0;
left[first[d]] = first[d + 1];
buildt(d + 1, s2, i - 1);//zuo
}
else if (i == s2) {
left[first[d]] = 0;
right[first[d]] = first[d + 1];
buildt(d + 1, i + 1, e2);//you
}
else {
right[first[d]] = first[d + i - s2 + 1];
left[first[d]] = first[d + 1];
buildt(d + i - s2 + 1, i + 1, e2);//you
buildt(d + 1, s2, i - 1);//zuo
}
}
7-3 文字编辑
一篇文章由n个汉字构成,汉字从前到后依次编号为1,2,……,n。
有四种操作:
A i j表示把编号为i的汉字移动编号为j的汉字之前;
B i j表示把编号为i的汉字移动编号为j的汉字之后;
Q 0 i为询问编号为i的汉字之前的汉字的编号;
Q 1 i为询问编号为i的汉字之后的汉字的编号。
规定:1号汉字之前是n号汉字,n号汉字之后是1号汉字。
输入格式:
第1行,1个整数T,表示有T组测试数据, 1≤T≤9999.
随后的每一组测试数据中,第1行两个整数n和m,用空格分隔,分别代表汉字数和操作数,2≤n≤9999,1≤m≤9999;第2至m+1行,每行包含3个常量s、i和j,用空格分隔,s代表操作的类型,若s为A或B,则i和j表示汉字的编号,若s为Q,i代表0或1,j代表汉字的编号。
输出格式:
若干行,每行1个整数,对应每个询问的结果汉字编号。
输入样例:
在这里给出一组输入。例如:
1
9999 4
B 1 2
A 3 9999
Q 1 1
Q 0 3
输出样例:
在这里给出相应的输出。例如:
4
9998
代码长度限制
16 KB
时间限制
1000 ms
内存限制
2 MB
思路:
用next last数组初始化为对应位置然后按要求修改 查询即可
参考代码:
#include<stdio.h>
int read() {
int f = 0, x = 0;
char ch = getchar();
while (!(ch >= '0' && ch <= '9')) f |= (ch == '-'), ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
void input() {
int t = read();
while (t--) {
int n = read(), m = read();
int next[100001], last[100001];
for (int i = 1; i <= n; ++i) next[i] = i + 1, last[i] = i - 1;//next和last储存前移和后移一位的数组 并循环进位
next[n] = 1;
last[1] = n;
for (int i = 1; i <= m; ++i) {
char ch;
scanf("%c", &ch);
int a = read(), b = read();
switch (ch) {
case 'A': {
if (last[b] == a) continue;
next[last[a]] = next[a];
last[next[a]] = last[a];
last[a] = last[b];
last[b] = a;
next[last[a]] = a;
next[a] = b; break;
}
case 'B': {
if (next[b] == a) continue;
next[last[a]] = next[a];
last[next[a]] = last[a];
next[a] = next[b];
next[b] = a;
last[next[a]] = a;
last[a] = b; break;
}
case 'Q': {
if (a) printf("%d\n", next[b]);
if (!a) printf("%d\n", last[b]); break;
}
}
}
}
}
int main() {
input();
return 0;
}
7-4 方案计数
组装一个产品需要 n 个零件。生产每个零件都需花费一定的时间。零件的生产可以并行进行。有些零件的生产有先后关系,只有一个零件的之前的所有零件都生产完毕,才能开始生产这个零件。如何合理安排工序,才能在最少的时间内完成所有零件的生产。在保证最少时间情况下,关键方案有多少种,关键方案是指从生产开始时间到结束时间的一个零件生产序列,序列中相邻两个零件的关系属于事先给出的零件间先后关系的集合,序列中的每一个零件的生产都不能延期。
输入格式:
第1行,2个整数n和m,用空格分隔,分别表示零件数和关系数,零件编号1..n,1≤n≤10000, 0≤m≤100000 。
第2行,n个整数Ti,用空格分隔,表示零件i的生产时间,1≤i≤n,1≤Ti≤100 。
第3到m+2行,每行两个整数i和j,用空格分隔,表示零件i要在零件j之前生产。
输出格式:
第1行,1个整数,完成生产的最少时间。
第2行,1个整数,关键方案数,最多100位。
如果生产不能完成,只输出1行,包含1个整数0.
输入样例:
在这里给出一组输入。例如:
4 4
1 2 2 1
1 2
1 3
2 4
3 4
输出样例:
在这里给出相应的输出。例如:
4
2
代码长度限制
16 KB
时间限制
200 ms
内存限制
64 MB
思路:
拓补排序求关键路径 AOEAOV什么的 用高精度求路径数
我不会 这里借用大佬的代码
参考代码:
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
#define f(i,a,b) for(int i=a;i<=b;i++)
#define _f(i,a,b) for(int i=a;i>=b;i--)
const int maxn = 1e4 + 5;
string add(string a, string b) {
vector<char> cup;
int tmp = 0;
int carry = 0;
char t1 = '0', t2 = '0';
while (!a.empty() || !b.empty()) {
if (!a.empty())
{
t1 = a.back();a.pop_back();
}
else t1 = '0';
if (!b.empty())
{
t2 = b.back();b.pop_back();
}
else t2 = '0';
tmp = t1 + t2 - 2 * '0' + carry;
if (tmp < 10) {
cup.push_back(tmp + '0');
carry = 0;
}
else {
cup.push_back(tmp % 10 + '0');
carry = 1;
}
}
if (carry == 1) {
cup.push_back('1');
}
string ans(cup.rbegin(), cup.rend());
return ans;
}
string path[maxn];
vector<int>edge[maxn];
int cost[maxn], degree[maxn], ecost[maxn];
int n, m;
queue<int>q;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m;
f(i, 1, n)cin >> ecost[i];
while (m--) {
int u, v;
cin >> v >> u;
edge[u].push_back(v);
degree[v]++;
}
f(i, 1, n) {
if (degree[i]==0) {
q.push(i);
cost[i] = ecost[i];
path[i] = "1";
}
}
f(i, 1, n) {
if (q.empty()) {
cout << "0";
return 0;
}
int u = q.front();q.pop();
while (!edge[u].empty()) {
int v = edge[u].back();
edge[u].pop_back();
degree[v]--;
if (cost[v] < cost[u] + ecost[v]) {
cost[v] = cost[u] + ecost[v];
path[v] = path[u];
}
else
if (cost[v] == cost[u] + ecost[v])
path[v] = add(path[v], path[u]);
if (!degree[v])q.push(v);
}
}
string ans ("0");
int lenth = -1;
f(i, 1, n) {
if (lenth < cost[i]) {
ans = path[i];
lenth = cost[i];
}
else if (lenth == cost[i]) {
ans = add(ans, path[i]);
}
}
cout << lenth << "\n";
cout << ans;
return 0;
}