第一题 序列调度
有一个N个数的序列A:1,2,……,N。有一个后进先出容器D,容器的容量为C。如果给出一个由1到N组成的序列,那么可否由A使用容器D的插入和删除操作得到。
输入格式:
第1行,2个整数T和C,空格分隔,分别表示询问的组数和容器的容量,1≤T≤10,1≤C≤N。
第2到T+1行,每行的第1个整数N,表示序列的元素数,1≤N≤10000。接下来N个整数,表示询问的序列。
输出格式:
T行。若第i组的序列能得到,第i行输出Yes;否则,第i行输出No,1≤i≤T。
输入样例:
在这里给出一组输入。例如:
2 2
5 1 2 5 4 3
4 1 3 2 4
输出样例:
在这里给出相应的输出。例如:
No
Yes
解题思路
刚开始理解题意花了很久,后面懂了,实质上就是能否让自然数序列A通过在容器栈D中的变化得到给出的序列,也就是说A序列的输出,必须要经历入栈和出栈。那么我们里面用一个循环,从1开始,把小于等于第一个数的自然数入栈,比如第一个要输出的数字是5,那就把1到5全部入栈,然后,判断是否栈爆,然后出栈一个,接着就在这个循环里面判断就可以了,如果栈顶大于要输出的数字,那就肯定无法获得了,直接输出no结束,因为如果把栈顶出了,就没办法获得栈顶这个数字了。代码如下
#include<iostream>
#include<stack>
using namespace std;
stack<int>apex;
int judge;
int stack_in[10001];
int main() {
int i, j, k;
int n, size;
cin >> n >> size;//输入组数和容器大小
for (k = 1; k <= n; k++) {
int number;
cin >> number;
judge = 1;
for (i = 1; i <= number; i++) {
cin >> stack_in[i];
}
i = 1;
while (!apex.empty())
apex.pop();
for (j = 1; j <= number; j++) {
if (!apex.empty() && apex.top() == stack_in[j]) {
apex.pop();
continue;
}//栈顶元素相等就出栈
if (!apex.empty()&&apex.top()> stack_in[j]) {
judge = 0;
cout << "No" << endl;
break;
}//如果大于,肯定得不到,直接结束
while (i <= stack_in[j]) {
apex.push(i);
i++;
}
if (apex.size()>size) {
judge = 0;
cout << "No" << endl;
break;
}
apex.pop();//在这里注意先判断是否超出大小,再进行出栈
}
if(judge == 1)
cout << "Yes" << endl;
}
return 0;
}
第二题 稀疏矩阵之差
矩阵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
解题思路
题目已经提示用三元组存储了,这里我用vector来存储,用一个大的结构体来存储矩阵,然后再用一个小的结构体存储对应的点,适用稀疏矩阵。本题主要考察存储,其他没有什么难点。
反思:太久没打代码,用了cout输出,最后一个点没过,考试的时候摆烂了,后面意识到改成printf就能过。代码如下
#include <iostream>
#include <vector>
using namespace std;
struct Node {
int row;
int column;
int value;
};
struct Matrix {
int rows;
int columns;
int num;
vector<Node> data;
};
int main() {
int i;
Matrix a, b, c;
cin >> a.rows >> a.columns >> a.num;
for (i = 0; i < a.num; i++) {
Node node;
cin >> node.row >> node.column >> node.value;
a.data.push_back(node);
}
cin >> b.rows >> b.columns >> b.num;
for (i = 0; i < b.num; i++) {
int t;
Node node;
cin >> node.row >> node.column >> t;
node.value = -1 * t;
b.data.push_back(node);
}
if (a.rows != b.rows || a.columns != b.columns) {
cout << "Illegal!" << endl;
return 0;
}
c.rows = a.rows;
c.columns = a.columns;
c.num = 0;
i = 0;
int k = 0;
while (i < a.num && k < b.num) {
if (a.data[i].row < b.data[k].row || (a.data[i].row == b.data[k].row && a.data[i].column < b.data[k].column)) {
c.data.push_back(a.data[i]);
i++;
}//如果小于,就直接存进去
else if (a.data[i].row == b.data[k].row && a.data[i].column == b.data[k].column) {
int temp = a.data[i].value + b.data[k].value;
if (temp != 0) {
Node node;
node.row = a.data[i].row;
node.column = a.data[i].column;
node.value = temp;
c.data.push_back(node);
c.num++;
}
i++;
k++;
}//相等的时候要判断是否为0
else {
c.data.push_back(b.data[k]);
k++;
}
}
while (i < a.num) {
c.data.push_back(a.data[i]);
i++;
}
while (k < b.num) {
c.data.push_back(b.data[k]);
k++;
}
c.num = c.data.size();
cout << c.rows << " " << c.columns << " " << c.num << endl;
for (i = 0; i < c.num; i++) {
//cout << c.data[i].row << " " << c.data[i].column << " " << c.data[i].value << endl;
printf("%d %d %d\n", c.data[i].row, c.data[i].column, c.data[i].value);
}
return 0;
}
第三题 前缀查询
已知有n个单词,单词均由小写字母构成。给出一个字符串,请统计以该字符串为前缀的单词的数量。规定:一个单词是其自身的前缀。单词和字符串都不空,长度都不超过20。
输入格式:
第1行包含两个整数n和m,n≤10000,m≤10000,分别表示单词的个数和查询的个数。
接下来的n行,每行一个单词。
接下来的m行,每行一个字符串。
输出格式:
多行,每行一个整数,对应查询字符串的统计数量。
输入样例:
在这里给出一组输入。例如:
2 2
abc
acd
a
ac
输出样例:
在这里给出相应的输出。例如:
2
1
解题思路
本题暴力是过不了的....好多同学用了字典树,但是我没听过这玩意,所以就不用这个东西了。这题是可以用map来写的,是一种哈希的想法。假设有一个序列abcde,我们要查它的前缀,那么实际上就是a,ab,abc,abcd,abcde我们都用map来对应,所以这里的map我用的是string对应int,这里的map开的要是一个数组,第一个括号对应字符串长度,第二个括号对应string,然后判断数目的时候,就直接输出apex[s.size()][s]就好了,这里apex是用map开的。
反思:stl很重要..代码如下
#include<iostream>
#include<map>
using namespace std;
map<string, int>apex[21];
int read() {
int t=0; char ch = getchar();
while (ch < '0' || ch>'9')ch = getchar();
while (ch >= '0' && ch <= '9')t = (t << 1) + (t << 3) + (ch ^ 48), ch = getchar();
return t;
}
int main() {
int n, m;
n = read(), m = read();
for (int i = 1; i <= n; i++) {
string s1;
cin >> s1;
//cout << s1;
for (int len = 0; len < s1.size(); len++) {
string currhash = "";
for (int j = 0; j <= len; j++) {
currhash += s1[j];
}
apex[len + 1][currhash]++;
}
}
for (int i = 1; i <= m; i++) {
string s1;
cin >> s1;
//cout << s1;
cout << apex[s1.size()][s1] << endl;
}
return 0;
}
第四题 方案计数
组装一个产品需要 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
解题思路
考试摆烂懒得写,本题事实上就是求关键路劲也就是最长路的个数,然后有点特殊的是需要用高精度加法,这有一点麻烦。更新到某一点的时候,如果到这个点的距离大于最长距离,那么就更新最长距离,如果等于的话,就要进行路径相加,然后再对这个点的后继点进行更新,入度减少到0进栈,长度相等相加,长度大于更新。
反思:不能太久不写代码,不然脑子转的很慢,一堆bug。代码如下
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define N 100005
int front, back, maxPathLength;
int timeNeeded[N], inDegree[N], queue[N];
int countNodes, head[N], istance[N];
long long pathCount[N][105], longestPathCount[105];
vector<int> successors[N];
int read() {
int t = 0;
char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') {
t = (t << 1) + (t << 3) + (ch ^ 48);
ch = getchar();
}
return t;
}
void addCount(long long a[], long long b[]) {
int len = max(a[0], b[0]);
for (int i = a[0] + 1; i <= b[0]; ++i) a[i] = 0;
for (int i = b[0] + 1; i <= a[0]; ++i) b[i] = 0;
for (int i = 1; i <= len; ++i) {
a[i] += b[i];
if (a[i] >= 10) {
a[i] -= 10;
++a[i + 1];
}
}
if (a[len + 1])
a[0] = len + 1;
else
a[0] = len;
}
int main() {
int n, m;
n = read();
m = read();
for (int i = 1; i <= n; ++i) {
timeNeeded[i] = read();
istance[i] = timeNeeded[i];
}
for (int i = 1; i <= m; ++i) {
int x = read();
int y = read();
successors[x].push_back(y);
++inDegree[y];
}
front = 1;
back = 0;
for (int i = 1; i <= n; ++i) {
if (!inDegree[i]) {
queue[++back] = i;
istance[i] = timeNeeded[i];
pathCount[i][0] = 1;
pathCount[i][1] = 1;
}
}
if (front > back) {
cout << "0";
return 0;
}
int visitedCount = 0;
while (front <= back) {
int x = queue[front++];
++visitedCount;
if (istance[x] == maxPathLength) {
addCount(longestPathCount, pathCount[x]);
}
if (istance[x] > maxPathLength) {
maxPathLength = istance[x];
longestPathCount[0] = pathCount[x][0];
for (int i = 1; i <= longestPathCount[0]; ++i)
longestPathCount[i] = pathCount[x][i];
}
for (int i = 0; i < successors[x].size(); i++) {
int v = successors[x][i];
--inDegree[v];
if (!inDegree[v])
queue[++back] = v;
if (istance[x] + timeNeeded[v] == istance[v])
addCount(pathCount[v], pathCount[x]);
if (istance[x] + timeNeeded[v] > istance[v]) {
istance[v] = istance[x] + timeNeeded[v];
pathCount[v][0] = pathCount[x][0];
for (int i = 1; i <= pathCount[x][0]; ++i)
pathCount[v][i] = pathCount[x][i];
}
}
}
if (visitedCount < n) {
cout << "0";
return 0;
}
cout << maxPathLength << endl;
for (int i = longestPathCount[0]; i >= 1; --i)
cout << longestPathCount[i];
return 0;
}