先上题目。 
 For an electronic mail application you are to describe the SMTP-based communication that takes place 
 between pairs of MTAs. The sender’s User Agent gives a formatted message to the sending Message 
 Transfer Agent (MTA). The sending MTA communicates with the receiving MTA using the Simple 
 Mail Transfer Protocol (SMTP). The receiving MTA delivers mail to the receiver’s User Agent. After 
 a communication link is initialized, the sending MTA transmits command lines, one at a time, to the 
 receiving MTA, which returns a three-digit coded response after each command is processed. The 
 sender commands are shown below in the order sent for each message. There is more than one RCPT 
 TO line when the same message is sent to several users at the same MTA. A message to users at 
 different MTAs requires separate SMTP sessions. 
 HELO myname Identifies the sender to the receiver (yes, there is only one L) 
 MAIL FROM:< sender > Identifies the message sender 
 RCPT TO:< user > Identifies one recipient of the message 
 DATA Followed by an arbitrary number of lines of text comprising the message 
 body, ending with a line containing a period in column one. 
 QUIT Terminates the communication. 
 The following response codes are sent by the receiving MTA: 
 221 Closing connection (after QUIT) 
 250 Action was okay (after MAIL FROM and RCPT TO specifying an acceptable user, or completion 
 of a message) 
 354 Start sending mail (after DATA) 
 550 Action not taken; no such user here (after RCPT TO with unknown user) 
 Input 
 The input contains descriptions of MTAs followed by an arbitrary number of messages. Each MTA 
 description begins with the MTA designation and its name (1 to 15 alphanumeric characters). Following 
 the MTA name is the number of users that receive mail at that MTA and a list of the users (1 to 15 
 alphanumeric characters each). The MTA description is terminated by an asterisk in column 1. Each 
 message begins with the sending user’s name and is followed by a list of recipient identifiers. Each 
 identifier has the form user@mtaname. The message (each line containing no more than 72 characters) 
 begins and terminates with an asterisk in column 1. A line with an asterisk in column 1 instead of a 
 sender and recipient list indicates the end of the entire input. 
 Output 
 For each message, show the communication between the sending and receiving MTAs. Every MTA 
 mentioned in a message is a valid MTA; however, message recipients may not exist at the destination 
 MTA. The receiving MTA rejects mail for those users by responding to the RCPT TO command with 
 the 550 code. A rejection will not affect delivery to authorized users at the same MTA. If there is not 
 at least one authorized recipient at a particular MTA, the DATA is not sent. Only one SMTP session 
 is used to send a message to users at a particular MTA. For example, a message to 5 users at the same 
 MTA will have only one SMTP session. Also a message is addressed to the same user only once. The 
 order in which receiving MTAs are contacted by the sender is the same as in the input file. As shown 
 in the sample output, prefix the communication with the communicating MTA names, and indent each 
 non-empty communication line. No innecessary spaces should be printed.
Sample Input 
 MTA London 4 Fiona Paul Heather Nevil 
 MTA SanFrancisco 3 Mario Luigi Shariff 
 MTA Paris 3 Jacque Suzanne Maurice 
 MTA HongKong 3 Chen Jeng Hee 
 MTA MexicoCity 4 Conrado Estella Eva Raul 
 MTA Cairo 3 Hamdy Tarik Misa 
 * 
 Hamdy@Cairo Conrado@MexicoCity Shariff@SanFrancisco Lisa@MexicoCity 
 * 
 Congratulations on your efforts !! 
 –Hamdy 
 * 
 Fiona@London Chen@HongKong Natasha@Paris 
 * 
 Thanks for the report! –Fiona 
 * 
 * 
 Sample Output 
 Connection between Cairo and MexicoCity 
 HELO Cairo 
 250
MAIL FROM:< Hamdy@Cairo> 
 250 
 RCPT TO:< Conrado@MexicoCity> 
 250 
 RCPT TO:< Lisa@MexicoCity> 
 550 
 DATA 
 354 
 Congratulations on your efforts !! 
 –Hamdy 
 . 
 250 
 QUIT 
 221 
 Connection between Cairo and SanFrancisco 
 HELO Cairo 
 250 
 MAIL FROM:< Hamdy@Cairo> 
 250 
 RCPT TO:< Shariff@SanFrancisco> 
 250 
 DATA 
 354 
 Congratulations on your efforts !! 
 –Hamdy 
 . 
 250 
 QUIT 
 221 
 Connection between London and HongKong 
 HELO London 
 250 
 MAIL FROM:< Fiona@London> 
 250 
 RCPT TO:< Chen@HongKong> 
 250 
 DATA 
 354 
 Thanks for the report! –Fiona 
 . 
 250 
 QUIT 
 221 
 Connection between London and Paris 
 HELO London 
 250 
 MAIL FROM:< Fiona@London> 
 250 
 RCPT TO:< Natasha@Paris> 
 550 
 QUIT 
 221
这道题目是刘汝佳大神的《算法竞赛入门经典》书中(因为这本书封面是紫色的,所以我又将这本称作紫书)的一道让我们熟悉C++STL用法的一道题目。紫书中已经给出了示例代码和题解。我的AC代码也是顺着刘神的思路写的。其中用到了**C++11新标准的新特性**,编译环境是开了C++11标准的CodeBlocks&mingw32-g++。如果你的编译器不通过的话,开一下编译器的C++11标准,在CodeBlocks16.01编译器菜单栏,点击Settings->Compiler,打开Global compiler settings界面,将"Have g++ follow the C++11 ISO C++ language"选项打上勾,最后点击OK。或者去掉代码中的C++11新特性语法就好了。
题目的意思大概就是模拟发送邮件时MTA之间的交互过程。英文好的看原题目就懂了,不懂的就有道翻译一下。理解透了题目意思,这道题就迎刃而解了。
下面给出我的AC代码:
  #include<iostream>
#include<set>
#include<string>
#include<vector>
#include<map>
using namespace std;
const string Space = " ";     //五个空格
int main()
{
    int n{ 0 };
    string str1, str2;
    set<string>address, vis;    //address->存放所有的MTA经处理后要联系的地址,vis->存放从address中已经解析过的地址
    vector<string>mta,users;    //mta->所有需要连接的MTA users->存放从post中取出的某个mta对应的要联系的所有用户
    map<string, vector<string> >post;//存放每个MTA需要发送的用户,注意"vector<string> >post"中后面的两个">"中间要间隔一个空格,以免有些编译器误认为是“>>”操作符
    while (cin >> str1 && str1 != "*") {//读入数据
        cin >> str1 >> n;
        while (n--) {
            cin >> str2;
            address.insert(str2 + "@" + str1);//处理地址,注意括号里是str2在前面,否则联系人搞反了可就wrong answer了
        }
    }
    while (cin >> str1 && str1 != "*") {
        mta.clear();       //清除各个容器
        vis.clear();
        post.clear();
        auto pos = str1.find('@');
        auto mta1 = str1.substr(pos + 1); //解析MTA
        while (cin >> str2 && str2 != "*") {
            pos = str2.find('@');
            auto mta2 = str2.substr(pos + 1);
            if (vis.count(str2))continue; //如果前面已经解析过这个地址了就直接跳过这个地址
            vis.insert(str2);  //每解析一个地址,就把这个地址记录下来,防止重复解析
            if (!post.count(mta2)) {//如果是一个新的MTA就存入mta中
                mta.push_back(mta2);
                post[mta2] = vector<string>();
            }
            post[mta2].push_back(str2);
        }
        string email, line;
        getline(cin, line);//“吃掉”第一封邮件正文内容前一行
        while (getline(cin, line) && line[0] != '*') {
            email += Space + line + "\n";  //将邮件内容按输出格式处理后存到string变量email中
        }
        for (vector<string>::size_type i = 0; i != mta.size(); i++) {
            string mta3 = mta[i];
            users.clear();//这个清除一定不要忘了
            users = post[mta3];
            cout << "Connection between " << mta1 << " and " << mta3 << endl;
            cout << Space << "HELO " << mta1 << endl;
            cout << Space << "250" << endl;
            cout << Space << "MAIL FROM:<" << str1 << ">" << endl;
            cout << Space << "250" << endl;
            bool ok{ false };
            for (vector<string>::size_type j = 0; j != users.size(); j++) {
                cout << Space<<"RCPT TO:<" << users[j] << ">" << endl;
                if (address.count(users[j])) {//判断是否找到了对应的联系人地址
                    ok = true;
                    cout << Space << "250" << endl;
                }
                else cout << Space << "550" << endl;
            }
            if (ok) {//找到了就输出邮件内容
                cout << Space << "DATA" << endl;
                cout << Space << "354" << endl;
                cout << email << Space <<"." << endl;
                cout << Space << "250" << endl;
            }
            cout << Space << "QUIT" << endl;
            cout << Space << "221" << endl;
        }
    }
    return 0;
}

京公网安备 11010502036488号