jlu(2023)数据结构第四次上机

第一题 序列调度

有一个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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值