NEUQ-ACM week1

T1.h0094. 乒乓球

国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。

其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。

华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白11分制和21分制对选手的不同影响。

在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。

华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在11分制和21分制下,双方的比赛结果(截至记录末尾)。 

比如现在有这么一份记录,(其中W表示华华获得一分,L表示华华对手获得一分): 

WWWWWWWWWWWWWWWWWWWWWWLW 

在11分制下,此时比赛的结果是华华第一局11比0获胜,第二局11比0获胜,正在进行第三局,当前比分1比1。

而在21分制下,此时比赛结果是华华第一局21比0获胜,正在进行第二局,比分2比1。

如果一局比赛刚开始,则此时比分为0比0。 

你的程序就是要对于一系列比赛信息的输入(WL形式),输出正确的结果。

输入格式:

每个输入文件包含若干行字符串(每行至多20个字母),字符串由大写的W、L和E组成。

其中E表示比赛信息结束,程序应该忽略E之后的所有内容。

输出格式:

输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。

其中第一部分是11分制下的结果,第二部分是21分制下的结果,两部分之间由一个空行分隔。

输入样例:

WWWWWWWWWWWWWWWWWWWW
WWLWE

输出样例:

11:0
11:0
1:1

21:0
2:1

解决这道问题需要注意的几个点

1.如何记录比赛的数据-这里选择使用结构体,这样可以同时记录局数和每局各自得分

2.比赛结束的条件-一方首先得到11分并且分差大于二

解体思路

1.创建一个结构体

2.创建一个数组记录输入的数据

3.创建一个包含结构体的数组,将第二步创建的数组里边数据导入新创建的结构体数组来记录两位选手各自的得分和比赛的局数

4.创建两个函数分别计算11分制和21分制的结果

5.输出数据

代码实现如下(其实是第一次做的时候想不出来参考网上大佬的解法ww)

#include <iostream>
#include <cmath>
using namespace std;
void yiyi();
void eryi();
struct ju
{
	int a;
	int b;
};
int h1;
int h2;
char c[2000];
int main()
{
	
	for (int i = 0; i < 2000; i += 1)//记录比赛信息
	{
		char ch = getchar();
		if (ch == '\n')
		{
			i -= 1;//注意别漏
			continue;
		}
		else if (ch == 'E')
		{
			i -= 1;//注意别漏
			break;
		}
		else
		{
			c[i] = ch;
		}
	}
	
	h1 = h2 = 0;
	yiyi();
	cout << endl;
	eryi();
	return 0;
}
void yiyi()//记录十一分赛制结果
{
	ju j[200];
	for (int i = 0; i<200; i += 1)
	{
		j[i].a = 0;
		j[i].b = 0;//初始化结构体
	}
	int k = 0;
	for (; k < 2000; k += 1)
	{
		if (c[k] == 'W')
		{
			j[h1].a += 1;
		}
		else if(c[k]=='L')
		{
			j[h1].b += 1;
		}
		if ((j[h1].a >= 11 || j[h1].b >= 11) && (abs(j[h1].a - j[h1].b) >= 2))
		{
			h1+=1;//记录比赛局数
		}
	}
	for (int i = 0; i <= h1; i += 1)
	{
		cout << j[i].a << ':' << j[i].b;//输出每一局各自得分(用结构体好像比较好实现)
		cout << endl;
	}
}
void eryi()//记录二十一分赛制结果
{
	ju j[200];
	for (int i = 0; i < 200; i += 1)
	{
		j[i].a = 0;
		j[i].b = 0;
	}
	int k = 0;
	for (; k < 2000; k += 1)
	{
		if (c[k] == 'W')
		{
			j[h2].a += 1;
		}
		else if(c[k]=='L')
		{
			j[h2].b += 1;
		}
		if ((j[h2].a >= 21 || j[h2].b >= 21) && (abs(j[h2].a - j[h2].b) >= 2))
		{
			h2+=1;
		}
	}
	for (int i = 0; i <= h2; i += 1)
	{
		cout << j[i].a << ':' << j[i].b;
		if (i != h2)
		{
			cout << endl;//小细节,最后一行不换行
		}
	}
}

T2.7-2 高精度加法

对于输入的两个不超过100位数字的非负整数,给出两数之和。

输入格式:

在两行中分别给出两个不超过100位数字的非负整数

输出格式:

在一行中输出两数之和

输入样例:

123
12

输出样例:

135

需要注意的地方

1.怎么存储数据?一开始用long-long,发现会被卡数据,而且显然一百位用longlong是不够的。于是考虑用数组来存储输入的数

2.用数组怎么计算加法?-把每一位相加再考虑进位的情况,而且要把数组先倒过来才方便从低位开始加,而且进位的方式也要考虑

3.数组类型的转化(一开始不知道这个,结果输出一堆奇怪的数..)

思路

1.创建两个字符串数组来记录输入的数

2.把两个字符串数组变成int数组并倒转

3.逐位相加

4.倒序输出结果

代码如下

#include<bits/stdc++.h>
using namespace std;
char Arr1[1050],Arr2[1050];//因为要读取输入所以必须char类型(int会报错)
int arr3[1050] ,arr1[1050],arr2[1050];
int main()
{
    cin>>Arr1>>Arr2;
    for(int i=0;i<strlen(Arr1);i++) arr1[i]=Arr1[strlen(Arr1)-i-1]-'0';
    for(int i=0;i<strlen(Arr2);i++) arr2[i]=Arr2[strlen(Arr2)-i-1]-'0';//将字符数组变成整数数组,然后倒转
    int temp=0;   //用temp定义进位
    int len=max(strlen(Arr1),strlen(Arr2));//这里strlen不能用arr(类型不兼容)
    for(int i=0;i<len;i++)
    {
        arr3[i]=arr1[i]+arr2[i]+temp;
        temp=arr3[i]/10;    //算出要不要进位(注意不要用 temp=arr3[i]-10)
        arr3[i]=arr3[i]%10;  //处理进位(也要注意不要写成arr3[i]=arr3[i]-10)
    }
    if(temp!=0)
    {
        arr3[len]=temp;//如果最高位也要进位的话要多开一位空间
        for(int i=len;i>=0;--i)cout<<arr3[i];
        return 0;
    }
     for(int i=len-1;i>=0;--i)cout<<arr3[i];
     return 0;
}
       

T3.高精度求累加和

使用求和公式求1到N的累加和大家都会,但是如果把N值变大呢,比如100位的整数,那该怎么求?

输入格式:

输入在一行中给出1个位数不超过100位的整数N。

输出格式:

对每一组输入,在一行中输出1+2+3+……+N的值。

输入样例:

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

10

输出样例:

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

55

需要思考的问题

1.怎么存储数据(显然还是用数组啦)

2.怎么实现累加和运算-用高斯求和,这样就只要算一次乘法就ok了(好难想到)

3.还是数组类型的转化

解题思路

1.创建两个数组存储输入的数据

2.反转数组,把两个数组错开一位

3.相乘(要注意进位的实现)

4.倒序输出数据(注意要把前面的0去除)

代码如下

#include<iostream>
#include<string.h>
using namespace std;
#define max 202
int a[max],b[max],c[max];
int main()
{
	string s;cin>>s;
	int x,i,j;
	int len=s.size();
	for(int i=0;i<len;i++){
		a[len-i]=s[i]-'0';//反转
		b[len-i]=s[i]-'0';
	}
	b[1]++;//后面用到高斯求和--(1+n)*n*1/2,这里求的是(1+n)
	for(int i=1;i<len;i++){//考虑进位(可能连环进位)
		if(b[i]==10){
			b[i]=0;
			b[i+1]++;
		}
		else break;//只要有一个地方不用进位就可以berak了
	}
	for(int i=1;i<=len;i++){
		for(int j=1;j<=len;j++){
			c[i+j-1]+=a[j]*b[i];
			c[i+j]+=c[i+j-1]/10;
			c[i+j-1]%=10;//高精度乘法(体会一下)
		}
	}
	int lenc=2*len;//两个长度len的结果相乘最多长度变成2len
	for(int i=lenc;i>=1;i--){//把相乘结果÷2
		if(c[i]%2==0){
			c[i]/=2;
		}
		else{
			c[i-1]+=10;
			c[i]/=2;
		}
	} 
	while(c[lenc]==0&&lenc>1)  lenc--;//去掉前导0
	 for(int i=lenc;i>=1;i--) {
	 	cout<<c[i];
	 }		
}

T3.小步点(招新补题)

现在是跑步时间。

咖波需要依次经过地图上的五个点位才能完成任务,为了节省体力,他希望以最短的距离跑完这五个点位。

现在给出这五个点位的坐标,你需要帮咖波求出最短距离。(咖波可以从任意一个坐标开始跑步)

输入格式:

总共五行

第i行有两个整数xi​,yi​(−103≤xi​,yi​≤103),表示第i个点位的坐标值。

数据保证不存在坐标相同的点。

输出格式:

输出一个实数,表示最短的跑步距离(保留三位小数)

输入样例:

0 0
0 2
2 2
2 0
1 1

输出样例:

6.828

样例解释:

可选择从(0,0)点开始,依次经过(0,2),(1,1),(2,0),(2,2)

此时距离为:2+2​+2​+2=6.828,可以证明这是最短的路径。

需要思考的地方

1.如何存储每个坐标-开两个数组分别存x和y(一开始想用二维数组发现不太行)

2.怎么计算两点间距离-还要开一个数组表示这是第几个点位

3.怎么遍历所有情况????-用神奇的next_permutation函数(真没想到)

思路

1.创建3个数组初始化点坐标和点的位次

2.算出总长度

3.遍历其他情况,取总长度最小值输出

代码如下(emm这也是网上魔改来的)

include<bits/stdc++.h>
using namespace std;
int x[6],y[6],a[6];
double solve(){
	double n=0;
	for(int i=1;i<=4;++i){//因为下面有i+1所以这里i<=4即可
		int nowx=x[a[i]]-x[a[i+1]],nowy=y[a[i]]-y[a[i+1]];//x1-x2,y1-y2
		n+=sqrt(nowx*nowx+nowy*nowy);//sqrt[(x1-x2)^2+(y1-y2)^2]
	}
	return n;
}
double ans=INT_MAX;
int main(){
	for(int i=1;i<=5;++i){
		cin>>x[i]>>y[i];
		a[i]=i;
	}
	for(int i=1;i<=120;i++){//注意i<=120(5!)
		ans=min(ans,solve());
		next_permutation(a+1,a+6);// next_permutation()会取得[first,last)所标示之序列的下一个排列组合
	}	
	printf("%.3lf",ans);
}

一周学习总结

感觉这些题好多都好难想啊(哭)说实在的除了第二题是完全自己写的以外其他题目都是上网看看别人类似的题目怎么写然后再自己去写一遍,不过最后也总算是把这几个题目的思想啊代码实现啊给整明白了。确实学到了不少东西,而且有一些是很细节的地方比如char数组转化成int类型这是我之前根本没有想到的操作  (•ิ_•ิ)。还有这真是个需要花时间的东西啊!一题写两三个小时居然对于我来说算很正常的了(┬_┬)下周继续努力!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值