PTA程序设计第六周

dada

7-1 特殊约瑟夫问题 (30 分)

编号为1…N的N个小朋友玩游戏,他们按编号顺时针围成一圈,从第一个人开始按逆时针次序报数,报到第M个人出列;然后再从下个人开始按顺时针次序报数,报到第K个人出列;再从下一个人开始按逆时针次序报数,报到第M个人出列;再从下个人开始按顺时针次序报数,报到第K个人出列……以此类推不断循环,直至最后一人出列。请编写程序按顺序输出出列人的编号。

输入格式:

输入为3个正整数,分别表示N、M、K,均不超过1000。

输出格式:

输出为一行整数,为出列人的编号。每个整数后一个空格。

输入样例:

6 3 5

输出样例:

5 3 1 2 4 6 
​
#include<bits/stdc++.h>
using namespace std;
int n,m,k;

int main()
{
	cin>>n>>m>>k;
	int a[n];
	int j = 1;
	int flag = 0;
	for(int i=0;i<n;i++)
	{
		a[i] = 0;
	}
	
	for(int i=0;i<n;i++)
	{
		if(i%2==0)
		{
			flag = 0;
			while(flag < m - 1)
		    {
			 j --;
			 if(j<0)
			 j = n - 1;
		 	 if(a[j]==0)
		 	 {
		 	 	 flag ++;
			  }
		 	
		    }
            a[j] = 1;
		if(j==0) cout<<n<<" ";
		if(j>0) cout<<j<<" ";
		}
		if(i%2==1)
		{
		flag = 0;
		while(flag < k - 1)
		{
			 j ++;
			 if(j == n)
			 j = 0;
		 	 if(a[j]==0)
		 	 {
		 	 	 flag ++;
			  }
		}
            a[j] = 1;
		if(j==0) cout<<n<<" ";
		if(j>0) cout<<j<<" ";
		}
	}
	

}

​

7-2 高精度乘法 (20 分)

知识点:高精度

给定两个非负整数 A 和 B,请你计算 A×B 的值。
1≤A的长度≤100000。
0≤B≤10000。

输入格式:

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式:

共一行,包含 A×B 的值。

输入样例:

2
3

输出样例:

6
​
#include<stdio.h>
#include<string.h>
int max;
void add(char a[],char b[])
{
	int c[100010]={0},d[100010]={0},i,j,re[100010]={0};
	int len1 = strlen(a);
	int len2 = strlen(b);
	max = len1 + len2;
	for(i=len1-1,j=0;i>=0;i--)
	c[j++] = a[i] - '0';
	for(i=len2-1,j=0;i>=0;i--)
	d[j++] = b[i] - '0';
	for(i=0;i<len1;i++)
	{
		for(j=0;j<len2;j++)
		{
			re[i+j] += c[i] * d[j];
			re[i+j+1] +=  re[i+j] / 10;//关键所在
			re[i+j] = re[i+j] % 10;
		} 
 	}
   for(i=max-1;i>0;i--)
    {
    if(re[max-1]==0)
 	max --;
    }
    for(i=max-1;i>=0;i--)
	printf("%d",re[i]);
}
int main()
{
	char a[100010],b[100010];
	scanf("%s %s",a,b);
	add(a,b);
}

​

7-3 重排链表 (25 分)

给定一个单链表 L1​→L2​→⋯→Ln−1​→Ln​,请编写程序将链表重新排列为 Ln​→L1​→Ln−1​→L2​→⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。

输入格式:

每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。

接下来有N行,每行格式为:

Address Data Next

其中Address是结点地址;Data是该结点保存的数据,为不超过105的正整数;Next是下一结点的地址。题目保证给出的链表上至少有两个结点。

输出格式:

对每个测试用例,顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。

输入样例:

00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

输出样例:

68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1
​
#include<stdio.h>
struct node
{
    int x;
    int next;
}p[1000001];
int main()
{
    int before[100001];
    int after[100001];
    int i,j;
    int total,n,first,now,start,next_,value;
    scanf("%d %d",&start,&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d %d %d",&now,&value,&next_);
        p[now].x = value;
        p[now].next = next_;
    }
    int k=0;
    while(start!=-1)
    {
        before[k++] = start;
        start = p[start].next;
    }
    int length = k;
    k = 0;
    for(i=0,j=length-1;i<=j;)
    {
        if(i==j)
        after[k] = before[i++];
        else
        {
            after[k++] = before[j--];
            after[k++] = before[i++];
        }
    }
    for(i=0;i<k-1;i++)
    {
        printf("%05d %d %05d\n",after[i],p[after[i]].x,after[i+1]);
    }
    printf("%05d %d -1\n",after[k-1],p[after[k-1]].x);
    //  printf("%d %d",k,length);
        
}

​

7-4 符号配对 (20 分)

请编写程序检查C语言源程序中下列符号是否配对:/**/()[]{}

输入格式:

输入为一个C语言源程序。当读到某一行中只有一个句点.和一个回车的时候,标志着输入结束。程序中需要检查配对的符号不超过100个。

输出格式:

首先,如果所有符号配对正确,则在第一行中输出YES,否则输出NO。然后在第二行中指出第一个不配对的符号:如果缺少左符号,则输出?-右符号;如果缺少右符号,则输出左符号-?

输入样例1:

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) { /*/
        A[i] = i;
}
.

输出样例1:

NO
/*-?

输入样例2:

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) /**/
        A[i] = i;
}]
.

输出样例2:

NO
?-]

输入样例3:

void test()
{
    int i
    double A[10];
    for (i=0; i<10; i++) /**/
        A[i] = 0.1*i;
}
.

输出样例3:

YES
​
#include<bits/stdc++.h>
using namespace std;
int main()
{
	char ch,last='a';
	char a[10010],b[10010];
	int topa=1,topb=1,i;
	while(1)
	{
		if((ch=getchar())=='\n'&&last=='.')//先判断前面的 
		break;
		
		if(ch=='('||ch=='{'||ch=='['
		||ch==']'||ch==')'||ch=='}')
		a[topa++] = ch;
		if(ch=='*'&&last=='/')
		{
			a[topa++] = '<';
			last = 'a';
			continue;
		}
		if(ch=='/'&&last=='*')
		{
			a[topa++] = '>';
			last = 'a';
			continue;
		}
		last = ch;
	}
	for(i=1;i<topa;i++)
	{
		if(topb==1)
		{
			if(a[i]==']'||a[i]==')'||a[i]=='}'||a[i]=='>')
			{
				cout<<"NO\n";
				if(a[i]=='>')
				printf("?-*/");
				else
				printf("?-%c",a[i]);
				return 0;
			}
			if(a[i]=='['||a[i]=='('||a[i]=='{'||a[i]=='<')
			{
				b[topb++] = a[i];
			}
		}
		else
		{
			if(a[i]=='['||a[i]=='('||a[i]=='{'||a[i]=='<')
			{
				b[topb++] = a[i];
			}
			else if(a[i]==']'&&b[topb-1]=='['
			||a[i]=='}'&&b[topb-1]=='{'
			||a[i]=='>'&&b[topb-1]=='<'
			||a[i]==')'&&b[topb-1]=='(')
			{
				topb --;
			}
			else 
			{
				cout<<"NO\n";
				if(b[topb-1]=='<')
				printf("/*-?");
				else
				printf("%c-?",b[topb-1]);
				return 0;
			}
		}
	}
	if(topb==1)
	cout<<"YES";
	else//输出的是b数组里面的 剩下的是左边的 缺少的是右符号
	{
		cout<<"NO\n";
		if(b[topb-1]=='<')
		printf("/*-?");
		else
		printf("%c-?",b[topb-1]);
		return 0;
	}
}

​

 

7-5 彩虹瓶 (25 分)

彩虹瓶的制作过程(并不)是这样的:先把一大批空瓶铺放在装填场地上,然后按照一定的顺序将每种颜色的小球均匀撒到这批瓶子里。

假设彩虹瓶里要按顺序装 N 种颜色的小球(不妨将顺序就编号为 1 到 N)。现在工厂里有每种颜色的小球各一箱,工人需要一箱一箱地将小球从工厂里搬到装填场地。如果搬来的这箱小球正好是可以装填的颜色,就直接拆箱装填;如果不是,就把箱子先码放在一个临时货架上,码放的方法就是一箱一箱堆上去。当一种颜色装填完以后,先看看货架顶端的一箱是不是下一个要装填的颜色,如果是就取下来装填,否则去工厂里再搬一箱过来。

如果工厂里发货的顺序比较好,工人就可以顺利地完成装填。例如要按顺序装填 7 种颜色,工厂按照 7、6、1、3、2、5、4 这个顺序发货,则工人先拿到 7、6 两种不能装填的颜色,将其按照 7 在下、6 在上的顺序堆在货架上;拿到 1 时可以直接装填;拿到 3 时又得临时码放在 6 号颜色箱上;拿到 2 时可以直接装填;随后从货架顶取下 3 进行装填;然后拿到 5,临时码放到 6 上面;最后取了 4 号颜色直接装填;剩下的工作就是顺序从货架上取下 5、6、7 依次装填。

但如果工厂按照 3、1、5、4、2、6、7 这个顺序发货,工人就必须要愤怒地折腾货架了,因为装填完 2 号颜色以后,不把货架上的多个箱子搬下来就拿不到 3 号箱,就不可能顺利完成任务。

另外,货架的容量有限,如果要堆积的货物超过容量,工人也没办法顺利完成任务。例如工厂按照 7、6、5、4、3、2、1 这个顺序发货,如果货架够高,能码放 6 只箱子,那还是可以顺利完工的;但如果货架只能码放 5 只箱子,工人就又要愤怒了……

本题就请你判断一下,工厂的发货顺序能否让工人顺利完成任务。

输入格式:

输入首先在第一行给出 3 个正整数,分别是彩虹瓶的颜色数量 N(1<N≤103)、临时货架的容量 M(<N)、以及需要判断的发货顺序的数量 K。

随后 K 行,每行给出 N 个数字,是 1 到N 的一个排列,对应工厂的发货顺序。

一行中的数字都以空格分隔。

输出格式:

对每个发货顺序,如果工人可以愉快完工,就在一行中输出 YES;否则输出 NO

输入样例:

7 5 3
7 6 1 3 2 5 4
3 1 5 4 2 6 7
7 6 5 4 3 2 1

输出样例:

YES
NO
NO
​
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a,i,j;
    int n,m,k;
    cin>>n>>m>>k;
    for(i=0;i<k;i++)
    {
        stack<int> s;
        int flag = 0;
        for(j=0;j<n;j++)
        {
            cin>>a;
            if(a==flag + 1)
            {
                flag ++;
                while(!s.empty()&&s.top()==flag + 1)
                    {
                        s.pop();
                        flag ++;
                    }
            }
            else if(s.size()<m)
            {
                  s.push(a);//不能break;某一行剩下的元素会遗留到下一行
            }
        }
        if(flag == n)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
}

​

7-6 列车调度 (25 分)

火车站的列车调度铁轨的结构如下图所示。

两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?

输入格式:

输入第一行给出一个整数N (2 ≤ N ≤105),下一行给出从1到N的整数序号的一个重排列。数字间以空格分隔。

输出格式:

在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。

输入样例:

9
8 4 2 5 3 9 1 6 7

输出样例:

4
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[100001],i,j,k=0,m;
    int n;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>m;
           if(k==0||m>a[k-1])
           a[k++] = m;
           else{
               int low = 0,high = k - 1;
            int mid; 
               while(low<=high)
               {
                mid = (low+high)/2;//放在循环体内部 
                   if(m>a[mid])
                   {
                       low  = mid + 1;
                }
                else
                {
                    high = mid -1;
                }
            }a[mid] = m;
           }
    }cout<<k<<endl;
}

好的,这是一个著名的约瑟夫问题,可以使用循环链表的思想来解决。以下是C语言代码实现: ```c #include <stdio.h> #include <stdlib.h> typedef struct Node{ // 定义链表节点 int index; // 小朋友编号 struct Node *next; // 指向下一个节点的指针 }Node, *LinkedList; LinkedList createLinkedList(int n){ // 创建有n个节点的单向循环链表 LinkedList head = NULL, tail = NULL; for(int i = 1; i <= n; i++){ Node *newNode = (Node*)malloc(sizeof(Node)); // 动态分配内存 newNode->index = i; newNode->next = NULL; if(head == NULL){ head = tail = newNode; } else{ tail->next = newNode; tail = newNode; } } tail->next = head; // 尾节点指向头节点,形成循环链表 return head; } void deleteNode(LinkedList *list, Node *prev, Node *current){ // 删除当前节点,并返回下一个节点的指针 if(*list == *list->next){ // 链表只剩一个节点时的特殊情况 *list = NULL; } else{ prev->next = current->next; // 将前一个节点指向下一个节点 *list = current->next; // 修改头结点 } printf("%d ", current->index); // 输出当前节点的编号 free(current); // 释放内存 } void josephus(int n, int m){ LinkedList list = createLinkedList(n); // 创建链表 Node *prev = NULL, *current = list; while(list != NULL){ for(int i = 1; i < m; i++){ // 找到要删除的节点 prev = current; current = current->next; } deleteNode(&list, prev, current); // 删除节点 } } int main(){ int n, m; printf("请输入小朋友的个数n:"); scanf("%d", &n); printf("请输入要出列的位置m:"); scanf("%d", &m); printf("出列顺序为:"); josephus(n, m); return 0; } ``` 运行结果如下: ``` 请输入小朋友的个数n:5 请输入要出列的位置m:3 出列顺序为:3 1 5 2 4 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

herry_drj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值