JLU数据结构第七次上机实验解题报告

7-1 序列调度 (100 分)

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

作者 谷方明

单位 吉林大学

代码长度限制 16 KB

时间限制 100 ms

内存限制 10 MB

解法一:

思路:

解决本题使用模拟的方法会很好,使用两个指针(下标指针),一个指针A指向待查询序列,一个指针B指向原始序列,A从前向后指向当前待验证序列的各个元素,有两种情况符合要求:每次指向一个元素,若栈顶元素正好与之对应,则弹出,若栈顶元素小于当前A指向的元素,则移动B将原始序列入栈到当前B指向的元素为止,若这两个判断失败,则代表查询失败。

外层用while循环控制,循环条件为栈的元素数小于等于给定的最大栈容量,若出循环则失败,循环内判断B指针是否走到了待查询序列尽头,若是则成功并结束函数。

反思:一看到这个题就想用dfs把所有可能的序列穷尽,然后再比较,还想保存之前运行dfs的结果以便N相同时直接查询。看来纯属是自讨苦吃。首先dfs在这个题不好写,其次要保存结果支持查询也不好写。有时候感受到当前方法不可行了,就要立即切换,不要一条道走到黑。

代码实现:

#include <iostream>
#include <vector>
using namespace std;
vector <int> stk;
int T = 0, C = 0, N = 0;
int* shu=NULL;
int* chaxun = NULL;
void ceshi(){
	stk.push_back(-1);
	int cxpoint = 0, shupoint = 1;
	while (stk.size() < C+2) {//不能超过栈的最大容量
		if (chaxun[cxpoint] == stk.back()) {//相等弹栈
			stk.pop_back();
			cxpoint++;
		}
		else if (chaxun[cxpoint] > stk.back()) {//当前指向的数大于栈顶元素(栈顶元素始终最大)则从初始序列中选取元素入栈直到当前查询的元素
			for (shupoint; shupoint < chaxun[cxpoint] + 1; shupoint++) {
				stk.push_back(shu[shupoint]);
			}
		}
		else {
			printf("No\n");
			return;
		}
		if (cxpoint == N - 1) {
			printf("Yes\n");
			return;
		}
	}
	printf("No\n");
}
int main() {
	scanf("%d%d", &T, &C);
	shu = new int[10001];
	chaxun = new int[10000];
	for (int i = 0; i < 10001; i++){
		shu[i] = i;
	}
	for (int i = 0; i < T; i++) {
		scanf("%d", &N);
		for (int i = 0; i < N; i++) {
			scanf("%d", &chaxun[i]);
		}
		ceshi();
		stk.clear();
	}
}

7-2 最大最小差 (100 分)

对n 个正整数,进行如下操作:每一次删去其中两个数 a 和 b,然后加入一个新数:a*b+1,如此下去直到 只剩下一个数。所有按这种操作方式最后得到的数中,最大的为max,最小的为min,计算max-min。

输入格式:

第1行:n,数列元素的个数,1<=n<=16。

第2行:n 个用空格隔开的数x,x<=10。

输出格式:

1行,所求max-min。

输入样例:

在这里给出一组输入。例如:

3
2 4 3

输出样例:

在这里给出相应的输出。例如:

2

作者 谷方明

单位 吉林大学

代码长度限制 16 KB

时间限制 100 ms

内存限制 64 MB

解法一:

思路:

本题应当发现:若要查找最小元素,则要每次选最小的两个元素进行操作,最大亦然。

这让我想到了哈夫曼树的建树思路。

有两种办法:

1.大小根堆。

2.一次排序。

3.利用huffman树建树的方法,在一个数组中多次操作。

反思:这道题我又想用dfs。。。写起来倒是不难,结果运行起来时间复杂度爆炸式增长,到数据量到10以上基本上就跑很久都跑不出来了。然而我还想着应该是剪枝没有做好,一直在想办法剪枝优化。却忽略了那么简单自然的做法。有的题可能就是靠发现规律来解决的,而不是主要利用已有的结构和方法。

代码实现:

#include <iostream>
#include <queue>
using namespace std;
priority_queue<int,vector<int>,less<int>> small_dl;
priority_queue<int, vector<int>, greater<int>> big_dl;
int main() {
	int n = 0, cup = 0;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d", &cup);
		small_dl.push(cup);
		big_dl.push(cup);
	}
	for (int i = 0; i < n-1; i++) {
		cup = small_dl.top(); small_dl.pop();
		cup *= small_dl.top(); small_dl.pop();
		small_dl.push(++cup);
		cup = big_dl.top(); big_dl.pop();
		cup *= big_dl.top(); big_dl.pop();
		big_dl.push(++cup);
	}
	printf("%d", big_dl.top() - small_dl.top());
}

7-3 二叉树最短路径长度 (100 分)

给定一棵二叉树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

解法一:

思路:

本题如果能够发现根结点到某个结点的路径只有一条,将会很简单。

只需要在建树的同时按照给定的权值将路径算出来,也不需要虚源虚汇,直接找父亲的权加自己的权即可。

我还尝试了使用虚汇和不使用的情况下的基本优化Bellman—Ford算法。但是倒数第二个点超时,当时还犹豫了一下要不要优化,不过考虑到如果是特意卡Bellman—Ford的话SPFA也不会有什么变化。还是选择换方法。最后果然证明倒数第二个点数据量比最后一个小很多,就是专门用来卡Bellman—Ford的。

代码实现:

(里面可以看到Bellman—Ford的影子)

#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
#define INT_MAX 1<<28;
int* quan = NULL;
struct TreeNode {
    int val;
    int lenth;
    TreeNode* left;
    TreeNode* right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
vector<vector<pair<int, int>>> tu;
TreeNode** yingshe = NULL;
class Build {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int preb = 0, pree = preorder.size() - 1;
        int inb = 0, ine = inorder.size() - 1;
        return mybuildtree(preorder, inorder, preb, pree, inb, ine,0);
    }
    TreeNode* mybuildtree(vector<int>& preorder, vector<int>& inorder, int preb, int pree, int inb, int ine,int lenth) {
        if (preorder.size() == 0) {
            return NULL;
        }
        if (pree == preb) {
            TreeNode* root = new TreeNode(preorder[preb]);
            root->lenth = lenth + quan[root->val];
            yingshe[root->val] = root;
            return root;
        }
        if (preb > pree || inb > ine) {
            return NULL;
        }
        vector<int>::iterator it;
        it = inorder.begin();
        int j = 0;
        for (j = 0; j < inb; j++) {
            ++it;
        }
        int i = 0;
        while (*it != preorder[preb]) {
            ++it;
            ++i;
        }
        TreeNode* root = new TreeNode(preorder[preb]);
        root->left = mybuildtree(preorder, inorder, preb + 1, preb + i, inb, i + inb - 1,lenth+quan[root->val]);
        root->right = mybuildtree(preorder, inorder, preb + i + 1, pree, i + inb + 1, ine,lenth+quan[root->val]);
        root->lenth = lenth + quan[root->val];//关键,建树的时候算lenth
        yingshe[root->val] = root;
        //if (root->left)tu[root->val].push_back(make_pair(root->left->val, quan[root->val]));
        //if (root->right)tu[root->val].push_back(make_pair(root->right->val, quan[root->val]));
        return root;
    }
};
/*int* Bellman_Ford(TreeNode*root,int n) {
    int* dist = new int[n + 1];
    for (int i = 0; i < n + 1; i++) {
        dist[i] = INT_MAX;
    }
    dist[root->val] = 0;
    bool flag = false;
    for (int k = 0; k < n; k++) {
        flag = false;
        for (int i = 1; i < n + 1; i++) {
            for (int j = 0; j < tu[i].size(); j++) {
                if (dist[i] + tu[i][j].second < dist[tu[i][j].first]) {
                    dist[tu[i][j].first] = dist[i] + tu[i][j].second;
                    flag = true;
                }
            }
            if (flag) {
                break;
            }
        }
    }
    return dist;
}*/
/*
void travel(TreeNode* root,int n) {
    if (root == NULL) {
        return;
    }
    if(root->left)tu[root->val].push_back(make_pair(root->left->val, quan[root->val]));
    if(root->right)tu[root->val].push_back(make_pair(root->right->val, quan[root->val]));
    travel(root->left,n);
    travel(root->right,n);
}*/
int main() {
    Build a;
    int n = 0;
    int cup = 0;
    scanf("%d", &n);
    yingshe = new TreeNode * [n + 1];
    quan = new int[n + 1];
    //tu = vector<vector<pair<int, int>>>(n + 1);
    vector<int> preorder(n), inorder(n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &cup);
        preorder[i] = cup;
    }
    for (int i = 0; i < n; i++) {
        scanf("%d", &cup);
        inorder[i] = cup;
    }
    for (int i = 1; i < n+1; i++) {
        scanf("%d", &quan[i]);
    }
    TreeNode* root=a.buildTree(preorder,inorder);
    //travel(root,n);
    //int* ans = Bellman_Ford(root,n);
    /*for (int i = 1; i < n + 1; i++) {
        printf("%d", ans[i]+quan[i]);
        if (i < n) {
            printf(" ");
        }
    }*/
    for (int i = 1; i < n + 1; i++) {
        printf("%d", yingshe[i]->lenth);
        if (i < n) {
            printf(" ");
        }
    }
}

7-4 方案计数 (100 分)

组装一个产品需要 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

解法一:

思路:

类似于计算最短路条数的思想,一边拓扑排序一边访问结点, 由于活动在点上, 如果活动的最早开始时间可以被更新就更新,若找到一个不能被更新的就看看是否相等,相等就累加其条数。其中记录到达每个结点的最短路条数用string数组配合大数加法来实现。

代码实现:

#include<iostream>
#include<vector>
#include<queue>
using  namespace std;
string add(string a, string b) {
	vector<char> cup;
	int cuppp = 0;
	int jinwei = 0;
	char cupa = '0', cupb = '0';
	while (!a.empty() || !b.empty()) {
		if (!a.empty()) {
			cupa = a.back();
			a.pop_back();
		}
		else {
			cupa = '0';
		}
		if (!b.empty()) {
			cupb = b.back();
			b.pop_back();
		}
		else {
			cupb = '0';
		}
		cuppp = cupa + cupb - 2 * '0' + jinwei;
		if (cuppp < 10) {
			cup.push_back(cuppp % 10 + '0');
			jinwei = 0;
		}
		else {
			cup.push_back(cuppp % 10 + '0');
			jinwei = 1;
		}
	}
	if (jinwei == 1) {
		cup.push_back('1');
	}
	string ans(cup.rbegin(), cup.rend());
	return ans;
}
string dashu[10002];
vector<int> tu[10002];
int main(void) {
	ios::sync_with_stdio(false);//加速cin cout
	int rudu[10002];
	int daijia[10002];
	int sumdaijia[10002];
	int n = 0, m = 0;
	int p = 0, q = 0;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> sumdaijia[i];
	}
	for (int i = 0; i < m; i++) {
		cin >> p >> q;
		tu[p].push_back(q);
		rudu[q]++;
	}
	queue<int> dl;
	for (int i = 1; i <= n; i++) {
		if (0 == rudu[i]) {
			daijia[i] = sumdaijia[i];
			dl.push(i);
			dashu[i] = "1";
		}
	}
	int j;
	int now = 0;
	while (!dl.empty()) {
		now = dl.front();
		dl.pop();
		while (tu[now].size()!=0) {
			j = tu[now].back(); tu[now].pop_back();
			rudu[j]--;
			if (0 == rudu[j])
				dl.push(j);
			if (daijia[now] + sumdaijia[j] > daijia[j]) {
				dashu[j] = dashu[now];
				daijia[j] = daijia[now] + sumdaijia[j];
			}
			else if (daijia[now] + sumdaijia[j] == daijia[j]) {
					dashu[j] = add(dashu[j], dashu[now]);
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		if (1 == rudu[i]) {
			cout<<"0";
			exit(0);
		}
	}
	string ans("0"); 
	int  lenth = -1;
	for (int i = 1; i <= n; ++i) {
		if (lenth < daijia[i]) {
			ans = dashu[i];
			lenth = daijia[i];
		}
		else if (lenth == daijia[i]) {
				ans = add(ans, dashu[i]);
			}
	}
	cout << lenth <<"\n";
	cout << ans;

}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一次实验: 题目1 单链表相关算法的实验验证。 [实验目的] 验证单链表及其上的基本操作。 [实验内容及要求] 1、 定义单链表类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建单链表; 2)插入操作:分别在当前结点后、表头、表尾插入值为x的结点; 3)删除操作:分别删除表头结点、表尾结点和当前结点的后继结点; 4)存取操作:分别存取当前结点的值和单链表中第k个结点的值; 5)查找操作:查找值为x的元素在单链表中的位置(下标)。 题目2 分别给出堆栈、队列相关算法的实验验证。 [实验目的] 验证堆栈、队列及其上的基本操作。 [实验内容及要求](以队列为例) 1、 定义队列类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建队列; 2)插入操作:向队尾插入值为x的元素; 3)删除操作:删除队首元素; 4)存取操作:读取队首元素。 第二次实验 题目1 二叉树相关算法的实验验证。 [实验目的] 验证二叉树的链接存储结构及其上的基本操作。 [实验内容及要求] 1、 定义链接存储的二叉树类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建一棵二叉树,并对其初始化; 2)先根、中根、后根遍历二叉树(递归算法); 3)在二叉树中搜索给定结点的父结点; 4)搜索二叉树中符合据域条件的结点; 5)从二叉树中删除给定结点及其左右子树。 题目2 树和森林的遍历算法的实验验证。 [实验目的] 验证树和森林的遍历算法。 [实验内容及要求] 1、 定义左儿子—右兄弟链接存储的树类和森林类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建树和森林; 2)树和森林的先根遍历的递归和迭代算法; 3)树和森林的后根遍历的递归和迭代算法; 4)树和森林的层次遍历算法。 题目3 二叉查找树的验证实验。 [实验目的] 验证二叉查找树及其相关操作。 [实验内容及要求] 1、 定义二叉查找树的类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)实现二叉查找树结构; 2) 实现二叉查找树的查找、插入和删除等算法; 第三次实验 题目1 邻接表存储的图相关算法的实验验证。 [实验目的] 验证邻接表存的图及其上的基本操作。 [实验内容及要求] 1、 定义邻接表存储的图类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建一个邻接表存储的图; 2)返回图中指定边的权值; 3)返回图中某顶点的第一个邻接顶点; 4)返回图中某顶点关于另一个顶点的下一个邻接顶点的序号; 5)插入操作:向图中插入一个顶点,插入一条边; 6)删除操作:从图中删除一个顶点,删除一条边。 题目2 图的遍历算法的实验验证。 [实验目的] 验证图的遍历算法。 [实验内容及要求] 1、 定义邻接表存储的图。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建一个图; 2)图的深度优先遍历的递归算法; 3)图的深度优先遍历的迭代算法; 4)图的广度优先遍历算法。 第四次实验 折半插入排序,堆排序,快速排序 请阅读说明文档

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值