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