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
解法一:
思路:
代码实现:
#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;
}