0
点赞
收藏
分享

微信扫一扫

微信小程序生成链接或二维码的对比

UVA814 邮件传输的代理交互 解题报告

题目链接

https://vjudge.net/problem/UVA-814

题目大意

本题的任务为模拟发送邮件时MTA(邮件传输代理)之间的交互。所谓MTA,就是email地址格式user@mtaname的“后面部分”。当某人从user1@mta1发送给另一个人user2@mta2时,这两个MTA将会通信。如果两个收件人属y于同一个MTA,发送者的MTA只需与这个MTA通信一次就可以把邮件发送给这两个人。

输入每个MTA里的用户列表,对于每个发送请求(输入发送者和接收者列表),按顺序
输出所有MTA之间的SMTP(简单邮件协议)交互。协议细节参见原题。

发送人MTA连接收件人MTA的顺序应该与在输入中第一次出现的顺序一致。例如,若发件人是Hamdy@Cairo,收件人列表为Conrado@MexicoCity、Shariff@SanFrancisco、Lisa@MexicoCity,则Cairo应当依次连接MexicoCity和SanFrancisco。

如果连接某个MTA之后发现所有收件人都不存在,则不应该发送DATA。所有用户名均由不超过15个字母和数字组成。

解题思路

这题并没有太多思维上的难度,但是实现起来细节很多。

首先要考虑的是如何把每个MTA里的用户列表保存下来。一种方法是用一个map<string, vector< string >>,其中键是MTA名称,值是用户名列表。一个更简单的方法是用一个set< string >,值就是邮件地址,封装一个函数来解析出地址的MTA和用户名即可。(这里的用户列表set < string >是用来记录对应收件人是否存在的,在后续模拟连接到每个MTA后,要给这个MTA的哪些用户发送DATA,还是需要用到map<string, vector< string >>的)。

对于每个请求,首先读入发件人,分离出MTA和用户名,然后读入所有收件人,根据MTA出现的顺序进行保存到vector中,并且去掉重复(跳过不放入列表即可)。接下来读入邮件正文,最后按顺序依次连接每个MTA,检查并输出每个收件人是否存在,如果至少有一个存在,则输出邮件正文。按照题目要求一步步模拟即可。详细细节见代码和注释。

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
#define endl '\n';
const int maxn = 1e3 + 10;
const int INF = 0x3fffffff;
const int mod = 1e9 + 7;

// 拆解发件人地址s,解析出用户名user以及mta地址
void parseAddr(const string &s, string &user, string &mta) {
    int k = s.find('@');
    user = s.substr(0, k);
    mta = s.substr(k + 1);
}

void solve() {
    int k;
    set<string> address;
    
    // 输入所有的MTA,并将其转换为地址列表
    string s;
    while (cin >> s, s != "*") {
        cin >> s >> k;
        while (k--) {
            string t;
            cin >> t;
            address.insert(t + "@" + s);
        }
    }

    // 模拟
    while (cin >> s, s != "*") {
        string user1, mta1;
        parseAddr(s, user1, mta1);  // 解析发件人地址

        vector<string> mta;     // 所有需要建立链接的mta,按照输入顺序
        map<string, vector<string>> dest;   // 每个MTA需要发送的用户
        set<string> vis;        // 标记每个接受过该消息的用户,以免重复接收
        string t;
        while (cin >> t, t != "*") {
            string user2, mta2;
            parseAddr(t, user2, mta2);  // 解析收件人地址
            if (vis.count(t))       // 重复的收件人,忽略掉
                continue;
            vis.insert(t);
            if (!dest.count(mta2)) {
                mta.push_back(mta2);
                dest[mta2] = vector<string>();
            }
            dest[mta2].push_back(t);
        }

        // 输入邮件正文
        string data;
        cin.get();      // 把这一行的回车吃掉
        while (getline(cin, t) && t != "*") {
            data += "     " + t + "\n";
        }
        
        // 发送
        for (int i = 0; i < mta.size(); i++) {
            string mta2 = mta[i];
            vector<string> users = dest[mta2];
            string space5 = "     ";
            cout << "Connection between " << mta1 << " and " << mta2 << endl;
            cout << space5 << "HELO " << mta1 << endl;
            cout << space5 << "250\n";
            cout << space5 << "MAIL FROM:<" << s << ">" << endl;
            cout << space5 << "250\n";
            bool sendData = false;
            for (int j = 0; j < users.size(); j++) {
                cout << space5 << "RCPT TO:<" << users[j] << ">\n";
                if (address.count(users[j])) {
                    sendData = true;
                    cout << space5 << "250\n";
                } else {
                    cout << space5 << "550\n";
                }
            }
            if (sendData) {
                cout << space5 << "DATA\n";
                cout << space5 << "354\n";
                cout << data;
                cout << space5 << ".\n";
                cout << space5 << "250\n";
            }
            cout << space5 << "QUIT\n";
            cout << space5 << "221\n";
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout << fixed;
    cout.precision(18);

    solve();
    return 0;
}
举报

相关推荐

0 条评论