C++程序设计实践——杭电acm2072、2073、2074、2075、2076

杭电acm练习题

Day03—— ProblemID=2072

这个写不来于是去搜了下别人的代码,看懂以后我又自己背着写了一次,然后提交。
参考链接:大佬2072代码
意料之外的 果不其然, 第一次提交WrongAnswer了:
2072
错误的代码:

#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;
}

不知道是错在哪啊。
用大佬的代码试了一下是可以提交成功的,如下图:
大佬的2072
我估计问题就出在我写的对于word判断是否为#那里,所以我用大佬的代码运行试了以下输入:
大佬代码本地运行
也就是说,只有单独输入的#才看做程序结束,跟在单词后面的#不作为程序结束的标志。
我改了while那里的判断以后,又把clear提到前面,第二次提交,又是WrongAnswer。
2072第二次
于是我本地运行了一下我第二次提交的代码:
2072本地运行第二次
为什么别人的代码运行没问题呢?
2072clear提前面
经过多次尝试,我发现不是clear位置的问题,而是不能把stringstream ss(s);这句话拆成两句写,本来我是想把他拆成两句创建对象的放在while循环外面,就不用每次循环重新新建浪费时间和空间,在while循环里面只要给他赋值就行了,结果没想到这样会运行不成功。

但我是那么轻易就放弃的人吗?是的,我是。 当然不是。

所以我就试着在一次输出结束后再用stringstream调用一次clear函数,果不其然,运行成功了!如下图:
2072本地运行第三次
然后我再去官网提交代码,通过啦!哈哈哈哈哈哈哈~
2072Accepted
代码如下:

#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;
}

运行结果:
2072本地运行结果
小样,和我斗,╭(╯^╰)╮。不过感觉这次实验三的题比实验一和实验二的难很多啊。好了我知道我菜心里说说就得了啊
这个代码涉及的一些语句如果看不懂的话,可以点以下相应的链接学习一下:
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呢。
2073第一次提交
问题是这一次的代码我是在本地运行通过了的,input和output和事例都对的上,我还自己试验了几个也对了,那么问题出在哪呢?作为一个身经百战 脑子有坑的c++菜鸟,我用我和猴子差不多的容量的小脑瓜一想,估计问题又出在边界上,果不其然,用大佬的代码计算0 0 99 99,输出的是55444.045,而我的代码输出的是55444.047!一字之差就是WrongAnswer的原因 ,我估计出现这个问题的原因是精度不够,所以我把我代码里的float变量全部改成了double型,现在再去提交,~~诶没提呢~ 果然,通过了,快乐啊。
2073Accepted
代码如下:

#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;
}

运行结果:
2073本地运行结果
关于这道题,我一开始以为很难,难爆了,再想到昨天想了半天的2072,我整个人跟霜打得茄子一样感觉实验报告写完的希望十分渺茫,结果没想到,一会就写出来了,思路大概就是:输入的点坐标(x,y)肯定在端点为(0,x+y)和(x+y,0)的斜线上,然后把折线路径分为两种,一种是大三角形斜边(中间没有断开),一种是由许多长为根号2的线段组成的直线,找出两种折线的规律用循环相加就可以了。斜边那个规律很简单,线段组成的直线那个只要统计从1依次加到x+y,最后再加上点的x坐标。2073问题可以从求点(x1,y1)到(x2,y2)转换为这两个点分别到原点的折线长度之差。
听不懂我也没办法,直接看代码吧,我不知道怎么讲。



Day03—— ProblemID=2074

能一次性提交通过是我万万没想到的,代码之神终于开始光顾我了吗?什么鬼我在说啥我是谁我在哪
2074Accepted

#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;
}

运行结果:
2074本地运行结果
只要想得到用二维数组保存图案,再用for循环从内向外依次给二维数组赋值,先是中心,然后是上下左右,再继续上下左右,循环完将四个角赋值为空格,然后输出就行。
要注意n=1要单独考虑,因为1/2=0。



Day03—— ProblemID=2075

2075Accepted
代码如下:

#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;
}

运行结果:
2075本地运行结果
太简单了,一次性就提交通过了,这道题也没啥好说的,真的是实验三的题吗,我再去确认下。
实验三要求
竟然真的是,好的,下一道下一道。



Day03—— ProblemID=2076

第一次提交,WrongAnswer。
2076WrongAnswer
第二次把代码的精度改了提交,WrongAnswer。
2076WrongAnswer第二次
第三次提交,通过了。
2076Accepted
代码如下:

#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;
}

运行结果:
2076本地运行结果
这道题要注意的点还挺多:
1.小时数大于12时要减去12,度数之差大于180时要用360来减。
2.计算过程中的30/60这些要写成浮点数,如30.0/60.0。
3.result要设置为浮点数,才能保证精度。
4.最后输出时再用(int)强制转换符转换格式。
PS.我两次通过不了就是因为把result设置为int或者提前转换格式了。



最后的吐槽

实验三我选的五道题里面也就第一题难了点,但是全部写完还是花了我接近一天的时间,大多数时候是在自己吓自己平白浪费了时间。感觉越往后写越轻松了,话说我还是更想做倒数第二题那样难度的啊。


版权声明:本文为YYY217511483原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。