題目大意:
有n個人和m句話,有些話的說話人不明,要求是每個人不能連着說兩句話,每句話不能提到自己,看看能不能將這些話的說話人都找出來,答案可能不固定。
解題思路:
根據題目意思將問題簡化,建立dp[i][j]意思爲第 j 句話可能是 i 說的,首先明確說話人的話,將已知的說話人作爲唯一的可能對象,其他的話只要不是提到的人都作爲可能對象。接下來其實就是dfs找一條結果樹,只要滿足相鄰兩句話不是一個人說的就行了,但是直接爆搜的複雜度有點大,可以使用記憶化搜索,記錄所有可能解。最後輸出就好了。
代碼:
#include "iostream"
#include "cstdio"
#include "math.h"
#include "algorithm"
#include "string"
#include "string.h"
#include "vector"
#include "map"
#include "queue"
#include "assert.h"
using namespace std;
int T, n, m, memo[105][105], retuser[105];
string name[105], message[105];
bool dp[105][105];//false:j may be say message i
bool isok(char c) {
if ((c >= '0'&&c <= '9') || (c >= 'a'&&c <= 'z') || (c >= 'A'&&c <= 'Z'))
return true;
return false;
}
int cal(int id, int bef) {
if (id > m)
return memo[id][bef] = 1;
int &ret = memo[id][bef];
if (ret != -1)
return ret;
ret = 0;
for (int i = 1;i <= n;i++) {
if (!dp[id][i] && bef != i) {
ret = max(ret, cal(id + 1, i));
}
}
return ret;
}
int main() {
scanf("%d", &T);
while (T--) {
memset(dp, 0, sizeof(dp));
scanf("%d", &n);
map<string, int>mp;
for (int i = 1;i <= n;i++) {
cin >> name[i];
mp[name[i]] = i;
}
scanf("%d", &m);
getchar();
for (int i = 1;i <= m;i++) {
getline(cin, message[i]);
int len = message[i].length();
string temp = "";
if (message[i][0] != '?') {
for (int k = 0;k < len;k++) {
if (isok(message[i][k]))
temp += message[i][k];
else
break;
}//get the speaker's name
for (int k = 1;k <= n;k++)
dp[i][k] = true;
dp[i][mp[temp]] = false;
}
else {
for (int k = 0;k < len;k++) {
if (isok(message[i][k]))
temp += message[i][k];
else {
int id = 0;
if (mp.count(temp))
id = mp[temp];
dp[i][id] = true;
temp.clear();
}
}
int id = 0;
if (mp.count(temp))
id = mp[temp];
dp[i][id] = true;
}
}
memset(memo, -1, sizeof(memo));
int ret = cal(1, 0);
if (ret != 1)
puts("Impossible");
else {
int user;
for (int i = 1;i <= n;i++) {
if (memo[m + 1][i] == 1) {
user = i;
break;
}
}
int id = m;
while (1) {
retuser[id] = user;
if (id == 1)
break;
for (int i = 1;i <= n;i++) {
if (user != i&&memo[id][i] == 1) {
user = i;
break;
}
}
id--;
}
for (int i = 1;i <= m;i++) {
cout << name[retuser[i]];
int j;
for (j = 0;j < message[i].size();j++)
if (message[i][j] == ':')
break;
while (j < message[i].size())
putchar(message[i][j++]);
puts("");
}
}
}
return 0;
}