第六周PTA笔记 括号匹配调整+堆放石子+最大积分+168

括号匹配调整

如果通过插入“ +”和“ 1”可以从中得到格式正确的数学表达式,则将带括号的序列称为正确的。
例如,序列 "(())()","()"和 "(()(()))"是正确的,而")(","(()))("和"(()" 不是。
定义重新排序操作:选择括号序列的任意连续子段(子字符串),然后以任意方式对其中的所有字符进行重新排序。
当重新排序的子段的长度为t时,重新排序操作需要耗时t秒。
例如,对于“))((”,他可以选择子字符串“)(”并重新排序“)()(”(此操作将花费2秒)。
不难看出,重新排序操作不会改变左括号和右括号的数量。
现在,LD想花费最少的时间,通过任意次数(可能为零)执行重新排序操作来使括号序列变成正确的。
输入格式:
第一行包含一个整数n(1≤n≤1e6),表示序列的长度;
第二行包含一个长度为n的字符串,仅由字符‘(’和‘)’组成。
输出格式:
输出一个整数,表示使括号序列正确的最小秒数;如果不可能实现,则输出-1。

输入样例:
8
))((())(
输出样例:
6

思路:参考了网络上的一篇博客pta括号匹配调整(栈)。了解了一下思路后我是用数组来做的,对于本人来说比较好理解。进行完是否可以实现括号正确序列的判断后,再进行秒数多少的计算。要使秒数最短,就要使重新排序的字符串最短。当遇到'('和')'时,这时不需要交换;遇到')'和'('时,可以将其作为子字符串进行重新排序;若是除了这两种之外的情况,就是将字符存进另一个数组后,再进行判断,或者与已存入另一个数组的字符进行比较判断。

#include<stdio.h>
char s[1000000],a[1000000];
int main()
{
	int n,i,flag=0,t=0;
	scanf("%d %s",&n,s);
	if(n%2!=0){
		printf("-1");
		return 0;
	}//若输入的括号数为奇数则肯定不能实现括号序列正确
	else{
		for(i=0;i<n;i++)
			{
				if(s[i]=='(')flag++;
			}
		if(flag!=n/2){
			printf("-1");
			return 0;
			}//若左右括号的数不相等,则也不能实现括号序列正确
	}
	flag=0;	
	for(i=0;i<n;i++)
		{
				if(a[flag]!=0){
					if(a[flag]=='('&&s[i]==')')flag--;
					else if(a[flag]==')'&&s[i]=='('){
						t+=2;
						flag--;
					}
					else{
						flag++;
						a[flag]=s[i];
					}
				}
				else a[flag]=s[i];			
		 } 
	printf("%d",t);
	return 0;
 } 

堆放石子

有N堆石子,每堆石子有若干石头,所有石头的总数是N的倍数。
可以在任意一堆上取若干石头,进行移动。移动规则是:在第一堆上取的石子,只能移到第二堆;在第N堆上取的石子,只能移到N-1堆;其他堆上取的,可以移到相邻左边或者右边。如何用最少的移动次数使得每堆石子的数量一样多呢?
当N=4时,4堆石子数为:9、8、17、6
移动3次可以使4堆数目一样多:
从第3堆取4个石子放到第4堆(9、8、13、10)
从第3堆取3个放到第2堆(9、11、10、10)
从第2堆取1个放到第1堆(10、10、10、10)
输入格式:
第一行包含一个整数N(1<= N <=100),表示有N堆石子;
接着有N行,每行一个整数ai(1<= ai <=10000),表示第i堆石子的数量。
输出格式:
输出一个整数,表示使所有石子堆的石子均达到相等时需要的最少移动次数。

输入样例:
4
9 8 17 6
输出样例:
3

思路:参考了7-4堆放石子。这道题个人感觉很像均等🖊这题,于是我一开始完全是用均等🖊那道题的思路去做的。但其实这道题比我所提到的那题要简单一些(尽管我一点儿思路都没有)。不能左边右边都去想,这样会很乱,就是只想往左边搬石子,搬的个数用另一个数组来储存,要是该数为0,则不用搬运,要是为正就是往左搬,要是为负就是往右搬。

#include<stdio.h>
int b[105];
int main()
{
	int a[105],N,i,s=0,ave,t=0;
	scanf("%d",&N);
	for(i=0;i<N;i++)
		{
			scanf("%d",&a[i]);
			s+=a[i];
		}
	ave=s/N;
	for(i=1;i<N;i++)
		{
			b[i]=ave-a[i-1]+b[i-1];
		}
	for(i=0;i<N;i++)
		{
			if(b[i]!=0)t++;
		}
	printf("%d",t);
	return 0;
}

最大积分

给你一罐颜料,并规定写出1-9每个数字所用的颜料是指定量的,当你用这罐颜料写下的数字越大,你得到的积分越多。
那么,你能得到的最大积分是多少呢?
输入格式:
第一行包含一个整数n(0≤n≤1000),表示给定颜料量。
第二行包含九个正整数a1,a2,… ,a9,分别表示写下数字1-9所需要的颜料量。
输出格式
输出一个数,表示你能得到的最大积分;如果颜料连一个数字都不够写,那么输出-1。

输入样例:
2
9 11 1 12 5 8 9 10 6
输出样例:
33

思路1(仅供参考,有瑕疵):在判断了是否能写数字后,若可以,将每个数字所需的颜料进行比较,选择需要颜料少的,若两个数字需要的颜料一样,则选择数字大的,这个思路有两个点没过。

自己测了一下数据,例如这组

523
174 175 176 173 172 171 174 175 177

按照我的程序将会输出877,但正确答案是986,这是因为我的代码只考虑了局部,忽略了整体。

//瑕疵代码
#include<stdio.h>
#include<stdlib.h>
int cmp(const void*c,const void*d);
int a[10],b[100000]; 
int main()
{
	int n,i,max,t=0,x;
	scanf("%d",&n);
	for(i=0;i<9;i++)
		{
			scanf("%d",&a[i]);
		}
	for(i=0;i<9;i++)
		{
			if(n/a[i]>0)break;
			
		}
	if(i==9||n==0){
		printf("-1");
		return 0;
	}
	max=n/a[0];
	b[t]=1;
	while(n>0){
		for(i=1;i<9;i++)
			{
				if(max<=n/a[i]){
					max=n/a[i];
					b[t]=i+1;
				}
			}
		if(n>=a[b[t]-1])n-=a[b[t]-1];
		else break;
		t++;
		max=n/a[0];
		b[t]=1;
	}//这部分需要改进
	qsort(b,t,sizeof(int),cmp);
	for(i=0;i<t;i++)
		{
			printf("%d",b[i]);
		}
	return 0;
 } 
 int cmp(const void*c,const void*d)
 {
 	return *(int*)d-*(int*)c;
 }

思路2:参考了7-6最大积分。在此总结一下思路,首先将9个数字中所需要最少颜料找出来,通过这个确定位数,因为一个数字的大小首先是位数,其次是最高位数字,接着依次往下推。关键步骤在代码中将会标注。

//正确代码
#include<stdio.h>
#include<stdlib.h>
int cmp(const void*c,const void*d);
int a[10],b[100000]; 
int main()
{
	int n,i,min,t=0,x,r;
	min=1000000;
	scanf("%d",&n);
	for(i=0;i<9;i++)
		{
			scanf("%d",&a[i]);
			if(min>a[i])min=a[i];
		}
	if(n/min==0){
		printf("-1");
		return 0;
	}
	x=n/min;
	while(x!=0){
		r=n-(x-1)*min;
		for(i=8;i>=0;i--)
			{
				if(a[i]<=r){
					b[t]=i+1;
					break;
				}
			}
		n-=a[b[t]-1];	
		t++;
		x--;
		
	}//关键步骤
	qsort(b,t,sizeof(int),cmp);
	for(i=0;i<t;i++)
		{
			printf("%d",b[i]);
		}
	return 0;
 } 
 int cmp(const void*c,const void*d)
 {
 	return *(int*)d-*(int*)c;
 }

168

汉堡包在大街上大摇大摆的走着,看着手机上一道难倒数万人的小学数学题:
1 + 1 = 0
1 + 6 = 1
6 + 6 = 2
8 + 1 = 2
8 + 6 = 3
汉堡包看完之后发现上面这些加法的答案就是看1,6,8中圈圈的个数嘛!
突然之间,所有大厦上的LED屏幕上的广告全部变成数字1,6,8三个数字的随机闪现。
现给你一块n*m的LED屏幕,上面有且仅有一个数字(1,6,or 8),请你输出你看见的那个字母。
输入格式:
第一行输入两个整数n,m(2<= m, n <= 1000);
接下来n行,每行由m个数字0和1组成,其中1表示数字1,6,8的组成部分。
输出格式:
输出一个整数,代表图形表示的数字。

输入样例:
7 7
0 0 0 0 0 0 0
0 0 1 1 1 0 0
0 0 1 0 1 0 0
0 0 1 1 1 0 0
0 0 1 0 1 0 0
0 0 1 1 1 0 0
0 0 0 0 0 0 0
输出样例:
8

思路1(有bug):通过在1中遍历到0的第一行来判断(先确定一个以1为边界的范围),如果改行的末尾是1,则输出8,若是0,则输出6。若没有0,那就是1了。但是这样做导致了一个点出错,我想应该是这种情况导致的。但如果没有这种情况,我觉得我对于这题的思路还算是清晰,哈哈哈哈哈哈哈哈哈哈哈哈

后来经过询问,发现一直没有过的那个点可能是这个亚子的。

7 7
0 0 0 0 0 0 0
0 0 1 1 1 1 1
0 0 1 1 0 0 0
0 0 1 1 1 1 1
0 0 1 1 0 0 0
0 0 1 1 1 1 1
0 0 0 0 0 0 0

该数据输出为8,是没有边界的,而我的方法将会把上面的数据判断为6。

//瑕疵代码,仅供参考
#include<stdio.h>
char s[1005][1005];
int main()
{
	int n,m,i,j,x1,x2,y1,y2,x;
	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++) 
				{
					scanf(" %c",&s[i][j]);
				}
		}
	for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++)
				{
					if(s[i][j]=='1'){
						x=j;
						x1=i;
						y1=j;
						while(s[i][j]=='1'){
							j++;
						}
						y2=j;
						j=x;
						while(s[i][j]=='1'){
							i++;
						}
						x2=i;
						i=n;
						break;
					}
				}
		}//确定关于1的范围的部分
	for(i=x1;i<x2;i++)
		{
			for(j=y1+1;j<y2;j++)
				{
					if(s[i][j]=='0'){
						if(s[i][y2-1]=='1'){
							printf("8");
							return 0;
						}
						else{
							printf("6");
							return 0;
						}
					}
				}
		}//判断部分
printf("1");
	
	
	return 0;
}

思路2:由于自己的方法不可行,于是琢磨了一下朋友的思路。通过判断每一行1的个数的种类来判断该数为什么。例如,对于8,总共有两种1,就像题目当中一种是三个1,还有一种是两个1。总结规律可得,对于数字1只有一种1;数字6有三种1;数字8有两种1。在这位同学的博客里有图示。

我是通过从第一行到最后一行遍历来判断1的种数,因为没有采取之前左上角和右下角确定1的范围的方法,因为可能会出现这种情况。

7 7 
0 0 0 0 0 0 0
0 0 1 1 1 0 0
0 0 1 0 1 0 0
0 0 1 1 1 1 0
0 0 1 0 0 1 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
//正确代码
#include<stdio.h>
char s[1005][1005];
int a[1005];
int main()
{
	int n,m,i,j,t=0,flag=0;
	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++) 
				{
					scanf(" %c",&s[i][j]);
				}
		}
	for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++)
				{
					if(s[i][j]=='1')t++;
				}
			if(a[t]==0&&t>0){
				a[t]=1;
				flag++;
			}
			t=0;	
		}
	if(flag==1)printf("1");
	else if(flag==2)printf("8");
	else printf("6");	
	return 0;
}

经过这次的做题,我再一次感觉自己真的是菜死了。/(ㄒoㄒ)/~~

posted @ 2020-04-03 19:51  尼古拉斯宝莉  阅读(696)  评论(0编辑  收藏  举报