0323,又是一周星期三,按道理该总结了。这周前几天写题比较多,后面事情多了起来,就没怎么写了。主要方向是洛谷的基本语法熟悉,PTA平台数据结构的一些题目。
0323附上: 题目比较多,所以文章可能有点长。
00 0317
00-1 P1116 车厢重组
00-1-1 题目描述
在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。
一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转180度,则可以把相邻两节车厢的位置交换,
用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列。
他退休后,火车站决定将这一工作自动化,其中一项重要的工作是编一个程序,
输入初始的车厢顺序,计算最少用多少步就能将车厢排序。
输入格式
共两行。
第一行是车厢总数N (N≤10000)。
第二行是 N 个不同的数表示初始的车厢顺序。
输出格式
一个整数,最少的旋转次数。
00-1-2 输入输出样例
输入
4
4 3 2 1
输出
6
00-1-3 解决代码
这道题,有一点意思,因为题目中没有告诉我们排序的操作过程,因此我们会去想示例的排序次数是怎么得出来的,所以我们写的程序就会是冒泡排序或者其他,再在冒泡排序中计数。
但我正要手写排序的时候,突然想起来实际上根本用不着,只输出移动次数意味着什么?意味着只需要统计一个数字前面有几个比它大,所以我们统计序列里每个数字前的count就可以啦。
题解最高赞也是我这个想法!-_-!
#include
using namespace std;
int main(){
int N,count = 0;
cin >> N;
int train[N] = {0};
for(int i = 0; i < N; i++){
cin >> train[i];
}
//查一个数前面有几个比他大
for(int i = 0; i < N; i++){
for(int j = 0; j < i; j++){
if(train[j] > train[i]){
count++;
}
}
}
cout << count;
return 0;
}
00-2 P1146 硬币翻转
00-2-1 题目描述
在桌面上有一排硬币,共N枚,每一枚硬币均为正面朝上。
现在要把所有的硬币翻转成反面朝上,规则是每次可翻转任意N-1枚硬币
(正面向上的被翻转为反面向上,反之亦然)。
求一个最短的操作序列(将每次翻转N-1枚硬币成为一次操作)。
输入格式
一个自然数N(N为不大于100的偶数)。
输出格式
第一行包含一个整数S,表示最少需要的操作次数。接下来的S行每行分别表示每次操作后桌上硬币的状态
(一行包含N个整数(0或1),表示每个硬币的状态:
0――正面向上,和1――反面向上,不允许出现多余空格)。
对于有多种操作方案的情况,则只需操作的字典序最小输出一种。
注:操作的字典序:对于一次操作,1表示翻转,0表示不反转。
但是需要你输出的是每一次操作完的状态,0表示正面朝上,1表示反面朝上。
00-2-2 输入输出样例
输入
4
输出
4
0111
1100
0001
1111
00-2-3 解决代码
这是个很简单的题,但是需要会读题......每次反转n-1等价于每次翻一个,再把n个全翻一次。
- 如果n是偶数,执行n次以上的操作第二步就被抵消了,只执行第一步,所以输入n就可以输出n作为答案;
- 如果n是奇数,相当于执行n次第一步,然后把所有的硬币翻一次面,这样就无法实现翻面。这种情况不可能。
接着就是每一组翻动都输出01序列就好了。
参考题解
#include
using namespace std;
int main(){
int n;
int coin[105] = {0};
cin >> n;
cout << n << endl;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(j!=i){
coin[j] = 1 - coin[j];
}
cout << coin[j];
}
cout <
01 0318
01-1 P1150Peter 的烟
01-1-1 题目描述
Peter 有 n 根烟,他每吸完一根烟就把烟蒂保存起来,
k(k>1)个烟蒂可以换一个新的烟,那么 Peter 最终能吸到多少根烟呢?
输入格式
每组测试数据一行包括两个整数 n, k(1 < n, k <= 10^8)。
输出格式
对于每组测试数据,输出一行包括一个整数表示最终烟的根数。
01-1-2 输入输出样例
输入 1
4 3
输出1
5
输入2
10 3
输出2
14
01-1-3 解决代码
这道题我想了一会儿,发现这件事情并不难,只需要一个循环就可以实现,只不过需要不断更新香烟的总数n,有一点剩余定理无限逼近的味道。但是题目是整数,所以总会到达。 可以举一个具体的迭代过程来看: 以4 3 为例:
i=1 <4, i%3!=0,继续;
i=2 <4,i%3!=0,继续;
i=3 <4, i%3==0, n++;
i=4 <5, i%3!=0, 继续;
i=5 =5, i%3!=0,继续;
i=6 >6,结束
#include
using namespace std;
int main(){
int n, k;
cin >> n >> k;
int count = n ;
int sum = k;
for(int i = 1; i <= n; i++){
if(i%k==0)n++;
}
cout << n;
}
01-2 P1151 子数整数
01-2-1 题目描述
01-2-2 输入输出样例
输入(0 输出 这道题不是很难,也让我意识到该复习一些算法和数据结构了。对于10000到30000的这些整数,每一个都求出它的三个子数,进行判断即可。 这道题提交了两次,原因是没有把题目看完全,题目中说若没有符合条件的,则输出"No",我没有考虑到,所以就有测试用例出错了。 这道题其实也没啥好说的,新建一个数组来记录两相邻元素的差,再取个绝对值,进行逐项判断。不过自己对于while的语法有些忘了,题目的要求也没有看清楚。 取绝对值的函数: 函数接口定义: 其中 裁判测试程序样例: 输入样例1: 输出样例1: 输入样例2: 输出样例2: 在mooc上用浙大的数据结构mooc来温习数据结构的知识,提供了一个高质量的题测平台PTA,当然要用起来,同时洛谷的入门题刷着也有点没意思了,每次只检查一些语法的问题以及思考的角度,对于高阶的结构和算法都不怎么涉及,是时候更进一步了,所以来了一道PTA的数据结构题... 虽然是二分查找但还是有一点折磨(虽然思路很简单但是做法很难一遍过)...平台的测试用例有一些刁钻,我拿当时学数据结构时已经通过的代码来提交也会报错。推荐一个二分查找讲的很好的视频.讲解的模板考虑很全面。 题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。 函数接口定义: 其中 裁判测试程序样例: 输入样例: 输出样例: 写一个二分已经有点难了,写有序链表合并确实也有点困难,不过这种困难来自于手法上的生疏,想法上有力了很多(也有可能是学习了后续课程算法设计的缘故,算法讲授的更宏观)。 这个问题很简单,分别遍历AB两个链表,逐结点比较,如果符合插入条件,则执行插入操作,如果不满足,指针继续向后移动,直到两者中的一者到达链表边界(空);然后将后续未比较内容直接链过来。 给定K个整数组成的序列{ N1, N2, ..., Nk },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1≤ i ≤ j ≤ K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。 本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下: 输入格式: 输出格式: 输入样例: 输出样例: 这道题半年前可能不太会,现在是有一定思路的。可以规定两个指针,一个指针负责从头到尾的主遍历确定头元素,第二个指针负责通过遍历改变尾元素,一首一尾就能确定一个子列。这道题还没有让输出最大子列和对应的那个子列,所以只需要设置一个max,不断更新即可。 所以很简单: 不过写的时候还是犯了低级错误,即输入输出数组的时候不是A[i],而是A[k],所以一直得不到正确结果。 给定一个序列K整数 {N1,N2, ...,NK}.连续子序列定义为 {Ni,Ni+1, ...,Nj} 其中1≤ i ≤ j ≤ K.最大子序列是具有其元素最大和的连续子序列。例如,给定序列 { -2, 11, -4, 13, -5, -2 },其最大子序列为 { 11, -4, 13 },最大和为 20。 现在,您应该找到最大总和,以及最大子序列的第一个和最后一个数字。 输入规格: 每个输入文件包含一个测试用例。每个案例占用两行。第一行包含正整数K (≤10000).第二行包含K数字,以空格分隔。 输出规格: 对于每个测试用例,在一行中输出最大和,以及最大子序列的第一个和最后一个数字。数字必须用一个空格分隔,但行尾不得有多余的空格。如果最大子序列不是唯一的,请输出索引最小的子序列我和j(如示例案例所示)。如果所有K数字为负数,然后其最大和定义为 0,并且您应该输出整个序列的第一个和最后一个数字。 示例输入: 示例输出: 这道题是上一道题的加强版,要求在输出最大子列和的同时输出这个子列的头尾元素。 就我上道题的思路,实现这一个升级是很简单的,增加两个标记位即可,遇到最大值就把头尾存下来。同时它强调输出下标较小的,所以要把上道题中的 ">=" 改成 ">" 。 第一次提交,感觉已经很周全了,出现了部分正确: 一个正数的情况出错。稍加检查发现我用来甄别在一个数出取得最大子列和的地方出错,写成了: 代码如下: 0320开了这个题,但是没写,去写计组的一个实验测试题了,有些难度,写了半天,所以就没有刷题。 0321打开又想了一会,觉得加法有点思路,乘法实现起来还是有点陌生,去写计组作业和微机接口mooc去了。 0322晚上终于得空,把实现了一下,参照了一下别的博主的思路。 设计函数分别求两个一元多项式的乘积与和。 输入格式: 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。 数字间以空格分隔。 输出格式: 输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。 数字间以空格分隔,但结尾不能有多余空格。 零多项式应输出。 设计函数分别求两个一元多项式的乘积与和。 输入格式: 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。 数字间以空格分隔。 输出格式:(!这里最重要!) 输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。 数字间以空格分隔,但结尾不能有多余空格。 零多项式应输出。 感觉用数组可以硬做,但是用链表其实更好,本来在回忆链表的一些操作,突然想起来自己明明报了浙大的mooc,打开一看,以上的题目居然都有实现过程,不禁感叹这个mooc质量之高。 参考思路 敲出来当然觉得很高兴,因为去年同期,这是很难的事情,但高兴早了,提交上去之后报错,全错,格式错误,仔细检查发现是自己的输出函数不对(下面代码输出函数的注释部分)。 又审了一遍题,发现没有认真理解题目关于输出格式的要求,要求 和多项式 和 积多项式 输出之间有一个换行,并且每一行最后不能有空字符,每一个结点的两个数之间有空格,结点和结点之间也有空格,我的代码是实现不了这些的,我只好应用了putchar(). 改进之后其实还是错的(20分拿了16分),是细节之错,我觉得很有记录的必要。见这段代码下方,先来看看近乎正确代码: 但是,这一版代码提交还是有问题的,截图如下: 出错原因也很简单:在进行异常处理即输出0 0 的时候,自己准备用来输出0 0 的结点没有挂上去,来看看输出函数printlist是怎么漏掉的 可以看到我的想法很好,如果是空链表,我新建一个结点,里面放两个0,然后把这个结点挂上去,再进行下面输出操作,就执行了,但是问题在于, 所以完整代码是:15
22555
25555
28555
30000
01-2-3 解决代码
#include
01-3 P1152 欢乐的跳
01-3-1 题目描述 & 输入输出样例
01-3-3 解决代码
#include
内,有abs()
函数,可以对整型变量求绝对值;
#include
内,有fabs()
函数,可以对浮点型变量求绝对值;#include
01-4 01-复杂度3 二分查找
01-4-1 题目描述
Position BinarySearch( List L, ElementType X );
List
结构定义如下:typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
L
是用户传入的一个线性表,其中ElementType
元素可以通过>、==、<进行比较,并且题目保证传入的数据是递增有序的。函数BinarySearch
要查找X
在Data
中的位置,即数组下标(注意:元素从下标1开始存储)。找到则返回下标,否则返回一个特殊的失败标记NotFound
。#include
01-4-2 输入输出
5
12 31 55 89 101
31
2
3
26 78 233
31
0
01-4-3 解决代码
//01二分查找
Position BinarySearch( List L, ElementType X ){
int head = 0, tail = L->Last+1;
while(head+1!=tail){
int mid = head+(tail-head)/2;
if(L->Data[mid]==X){
return mid;
}
if(L->Data[mid]>X){
tail = mid;
}
if(L->Data[mid]
01-5 02-线性结构1 两个有序链表序列的合并
01-5-1 题目描述
List Merge( List L1, List L2 );
List
结构定义如下:typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
L1
和L2
是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Merge
要将L1
和L2
合并为一个非递减的整数序列。应直接使用原序列中的结点,返回归并后的带头结点的链表头指针。#include
01-5-2 输入输出
3
1 3 5
5
2 4 6 8 10
1 2 3 4 5 6 8 10
NULL
NULL
01-5-3 解决代码
List Merge(List L1,List L2){
List L3,p,q,l0;
L3 = (List)malloc(sizeof(List));
l0=L3;
p = L1->Next;
q = L2->Next;
//算法编程里这种变量更容易敲,虽然项目里不喜欢
L3->Next = NULL;
while(p&&q)
{
if(p->Data<=q->Data)
{
l0->Next = p;
l0 = l0->Next;
p=p->Next;
}
else{
l0->Next = q;
l0 = l0->Next;
q=q->Next;
}
}
l0->Next = p?p:q;
// if(p)
// {
// l0->Next=p;
// }
// if(q)
// {
// l0->Next = q;
// }
L1->Next=NULL;
L2->Next=NULL;
//合并完成两链表置空,题目要求的事情一定要做
return L3;
}
02 0319
02-1 01-复杂度1 最大子列和问题
02-1-1 题目描述
输入第1行给出正整数*K* (≤100000);第2行给出*K*个整数,其间以空格分隔。
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。
02-1-2 输入输出
6
-2 11 -4 13 -5 -2
20
01-1-3 解决代码
//0319最大子列和
#include
02-2 01-复杂度2 Maximum Subsequence Sum
02-2-1 题目描述
02-2-2 输入输出
10
-10 1 2 3 4 -5 -23 3 7 -21
10 1 4
02-2-3 解决代码
for(int i = 0; i < K; i++){
count = A[i];
if(count>sum){
sum = A[i];
left = i;
right = i;
//应当是left = A[i],left和right都应该是。
}
//0319加强版的最大子列
//需要在输出最大子列和的同时输出首尾元素,用我的思路来讲,只需要增加两个标记位罢了。
#include
03 0320 / 0322
03-1 线性结构2 一元多项式的乘法与加法运算
03-1-1 题目描述
0 0
03-1-2 输入输出
0 0
03-1-3 解决思路以及细节问题
//0319两个一元多次多项式的相加
//感觉有数组可以硬做,但是用链表其实更好
#include
void printList(LNode* L){
//由于空链表需要输出 0 0,所以空时需要特别处理一下
if(L->next == NULL){//刚手敲掉了一个=
LNode *p = new LNode;
p->next = NULL;
p->coef = 0;
p->exp = 0;
}
...
}
if
语句的最后我没有把L->nex = p;
,所以产生了上面的错误。void printList(LNode* L){
//由于空链表需要输出 0 0,所以空时需要特别处理一下
if(L->next == NULL){//刚手敲掉了一个=
LNode *p = new LNode;
p->next = NULL;
p->coef = 0;
p->exp = 0;
L->next = p;
}
...
}
03-1-4 最终代码
//0319两个一元多次多项式的相加
//感觉有数组可以硬做,但是用链表其实更好
#include