杭电acm练习题
Day03—— ProblemID=2072
这个写不来于是去搜了下别人的代码,看懂以后我又自己背着写了一次,然后提交。
参考链接:大佬2072代码
意料之外的 果不其然, 第一次提交WrongAnswer了:
错误的代码:
#include <iostream>
#include <sstream>
#include <string>
#include <set>
using namespace std;
int main() {
string word;
string s;
set<string>allWords;
stringstream ss;
while (getline(cin, s)) {
if (s == "#")
break;
ss.str(s);
while (ss >> word && word != "#")
allWords.insert(word);
cout << allWords.size() << endl;
allWords.clear();
}
return 0;
}
不知道是错在哪啊。
用大佬的代码试了一下是可以提交成功的,如下图:
我估计问题就出在我写的对于word判断是否为#那里,所以我用大佬的代码运行试了以下输入:
也就是说,只有单独输入的#才看做程序结束,跟在单词后面的#不作为程序结束的标志。
我改了while那里的判断以后,又把clear提到前面,第二次提交,又是WrongAnswer。
于是我本地运行了一下我第二次提交的代码:
为什么别人的代码运行没问题呢?
经过多次尝试,我发现不是clear位置的问题,而是不能把stringstream ss(s);这句话拆成两句写,本来我是想把他拆成两句创建对象的放在while循环外面,就不用每次循环重新新建浪费时间和空间,在while循环里面只要给他赋值就行了,结果没想到这样会运行不成功。
但我是那么轻易就放弃的人吗?是的,我是。 当然不是。
所以我就试着在一次输出结束后再用stringstream调用一次clear函数,果不其然,运行成功了!如下图:
然后我再去官网提交代码,通过啦!哈哈哈哈哈哈哈~
代码如下:
#include <iostream>
#include <sstream>
#include <string>
#include <set>
using namespace std;
int main() {
string word;
string s;
stringstream ss;
set<string>allWords;
while (getline(cin, s)) {
if (s == "#")
break;
allWords.clear();
ss.str(s);
while (ss >> word)
allWords.insert(word);
cout << allWords.size() << endl;
ss.clear();
}
return 0;
}
运行结果:
小样,和我斗,╭(╯^╰)╮。不过感觉这次实验三的题比实验一和实验二的难很多啊。好了我知道我菜心里说说就得了啊
这个代码涉及的一些语句如果看不懂的话,可以点以下相应的链接学习一下:
C++ stringstream介绍,使用方法与例子
C++ getline函数用法详解
C++中set的用法
C++中set用法详解
再记录一下我对大佬代码写的批注:
#include <iostream>
#include <sstream>
#include <set>
#include <string>
using namespace std;
int main() {
string sentence;//定义一个字符串对象sentence
set<string> mySet;//定义一个set容器mySet,保存的数据类型为string
while (getline(cin, sentence)) {//用getline读取一整行,储存在字符串对象sentence中
//不用cin读取是因为:当 cin 读取数据时,它会传递并忽略任何前导白色空格字符(空格、制表符或换行符)。
//一旦它接触到第一个非空格字符即开始阅读,当它读取到下一个空白字符时,它将停止读取。
if (sentence == "#")//当读取的数据为#时
break;//结束程序
stringstream ss(sentence);//定义一个stringstream对象ss,ss从string对象sentence读取字符
string word;//定义一个字符串对象word
while (ss >> word)//将stringstream对象ss的第一段字符赋值给string对象word
//(因为ss被空格、换行符等符号分成一段一段的,所以可以一端一段的赋值)
mySet.insert(word);//mySet调用insert函数插入一个元素
//元素的值等于字符串对象word保存的字符串内容
cout << mySet.size() << endl;//mySet调用size函数计算set容器中元素的个数,并输出
mySet.clear();//mySet清除所有元素
}
return 0;
}
Day03—— ProblemID=2073
第一次提交,又是喜闻乐见的WrongAnswer呢。
问题是这一次的代码我是在本地运行通过了的,input和output和事例都对的上,我还自己试验了几个也对了,那么问题出在哪呢?作为一个身经百战 脑子有坑的c++菜鸟,我用我和猴子差不多的容量的小脑瓜一想,估计问题又出在边界上,果不其然,用大佬的代码计算0 0 99 99,输出的是55444.045,而我的代码输出的是55444.047!一字之差就是WrongAnswer的原因 ,我估计出现这个问题的原因是精度不够,所以我把我代码里的float变量全部改成了double型,现在再去提交,~~诶没提呢~ 果然,通过了,快乐啊。
代码如下:
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
double compute(int x, int y) {
int n;
double c, l, sum;
l = sqrt(2);
n = 0;
c = 0;
for (int i = 1; i <= x + y; i++)
c = c + sqrt(i * i + (i - 1) * (i - 1));
for (int i = 1; i < x + y; i++)
n = n + i;
n = n + x;
sum = n * l + c;
return sum;
}
int main() {
int n,x1,x2,y1,y2;
double result;
while (cin >> n) {
while (n--) {
cin >> x1 >> y1 >> x2 >> y2;
result = fabs(compute(x2, y2) - compute(x1, y1));
cout << setiosflags(ios::fixed) << setprecision(3) << result << endl;
}
}
return 0;
}
运行结果:
关于这道题,我一开始以为很难,难爆了,再想到昨天想了半天的2072,我整个人跟霜打得茄子一样感觉实验报告写完的希望十分渺茫,结果没想到,一会就写出来了,思路大概就是:输入的点坐标(x,y)肯定在端点为(0,x+y)和(x+y,0)的斜线上,然后把折线路径分为两种,一种是大三角形斜边(中间没有断开),一种是由许多长为根号2的线段组成的直线,找出两种折线的规律用循环相加就可以了。斜边那个规律很简单,线段组成的直线那个只要统计从1依次加到x+y,最后再加上点的x坐标。2073问题可以从求点(x1,y1)到(x2,y2)转换为这两个点分别到原点的折线长度之差。
听不懂我也没办法,直接看代码吧,我不知道怎么讲。
Day03—— ProblemID=2074
能一次性提交通过是我万万没想到的,代码之神终于开始光顾我了吗?什么鬼我在说啥我是谁我在哪 。
#include<iostream>
using namespace std;
int main() {
int n,mid;
bool flag=false;
char out, center;
char box[80][80];
while (cin >> n >> center >> out) {
if (flag == true)
cout << endl;
if (n == 1) {
cout << center<< endl;
flag = true;
}
else {
mid = n / 2;
box[mid][mid] = center;
for (int i = 1; i <= mid; i++) {
for (int j = mid - i; j <= mid + i; j++) {
box[mid - i][j] = out;
box[mid + i][j] = out;
box[j][mid - i] = out;
box[j][mid + i] = out;
}
swap(center, out);
}
box[0][0] = ' ';
box[0][n - 1] = ' ';
box[n - 1][0] = ' ';
box[n - 1][n - 1] = ' ';
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
cout << box[i][j];
cout << endl;
flag = true;
}
}
}
return 0;
}
运行结果:
只要想得到用二维数组保存图案,再用for循环从内向外依次给二维数组赋值,先是中心,然后是上下左右,再继续上下左右,循环完将四个角赋值为空格,然后输出就行。
要注意n=1要单独考虑,因为1/2=0。
Day03—— ProblemID=2075
代码如下:
#include<iostream>
using namespace std;
int main() {
int n,A,B;
while (cin >> n) {
while (n--) {
cin >> A >> B;
if (A % B == 0)
cout << "YES"<< endl;
else
cout << "NO"<< endl;
}
}
return 0;
}
运行结果:
太简单了,一次性就提交通过了,这道题也没啥好说的,真的是实验三的题吗,我再去确认下。
竟然真的是,好的,下一道下一道。
Day03—— ProblemID=2076
第一次提交,WrongAnswer。
第二次把代码的精度改了提交,WrongAnswer。
第三次提交,通过了。
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int main() {
int n;
double h, m, s;
while (cin >> n) {
double dh, dm, result;
while (n--) {
cin >> h >> m >> s;
if (h >= 12)
h = h - 12;
dh = h * 30.0 + m * (30.0 / 60.0) + s * (30.0 / 3600.0);
dm = m * 6.0 + s * (6.0 / 60.0);
result = fabs(dh - dm);
if (result > 180)
result = 360 - result;
cout << (int)result << endl;
}
}
return 0;
}
运行结果:
这道题要注意的点还挺多:
1.小时数大于12时要减去12,度数之差大于180时要用360来减。
2.计算过程中的30/60这些要写成浮点数,如30.0/60.0。
3.result要设置为浮点数,才能保证精度。
4.最后输出时再用(int)强制转换符转换格式。
PS.我两次通过不了就是因为把result设置为int或者提前转换格式了。
最后的吐槽
实验三我选的五道题里面也就第一题难了点,但是全部写完还是花了我接近一天的时间,大多数时候是在自己吓自己平白浪费了时间。感觉越往后写越轻松了,话说我还是更想做倒数第二题那样难度的啊。