题目大意:
有n个人和m句话,有些话的说话人不明,要求是每个人不能连着说两句话,每句话不能提到自己,看看能不能将这些话的说话人都找出来,答案可能不固定。
解题思路:
根据题目意思将问题简化,建立dp[i][j]意思为第 j 句话可能是 i 说的,首先明确说话人的话,将已知的说话人作为唯一的可能对象,其他的话只要不是提到的人都作为可能对象。接下来其实就是dfs找一条结果树,只要满足相邻两句话不是一个人说的就行了,但是直接爆搜的复杂度有点大,可以使用记忆化搜索,记录所有可能解。最后输出就好了。
我的解题思路
说话的顺序就是一个天然的序, 安排第i个人说话的时候,有两个限制条件, 1. 不能与前一个说话的人相同, 2. 不能出现在后面说话的句子里
那么DP 思想就很显然了。。。。。 F【i,j】 表示第i句话是否为第j个人说的。
转移方程也就so eazy了 , 我们可以通过枚举前一句话是由谁讲的,进行更新状态!!!! GOOD 好题啊艹
昂神代码来一发 233333
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n , m;
map<string , int> h;
string name[N] , str[N] , re[N];
bool f[N][N];
int g[N][N];
void print(int x , int y) {
if (x == 0) {
return;
}
print(x - 1 , g[x][y]);
cout << name[y] << re[x - 1] << endl;
}
void work() {
scanf("%d" , &n);
h.clear(); //名字编号
for (int i = 0 ; i < n ; ++ i) {
cin >> name[i];
h[name[i]] = i;
}
scanf("%d\n" , &m);
memset(f , 0 , sizeof(f)); // f【i,j】 = 1 表示 第i句话是第j个人说的 ........
memset(g , 0 , sizeof(g));
f[0][n] = 1;
for (int i = 0 ; i < m ; ++ i) {
getline(cin , str[i]);
re[i].clear();
}
for (int i = 0 ; i < m ; ++ i) {
string usr , buf = str[i];
int p = 0;
while (p < buf.size() && buf[p] != ':') {
usr += buf[p ++];
}
int q = p;
while (q < buf.size()) {
re[i] += buf[q ++];
}
set<int> mention;
while (p < buf.size()) {
string word;
while (p < buf.size() && isalnum(buf[p])) {
word += buf[p ++];
}
if (h.count(word)) { //存在该名单中
mention.insert(h[word]); // 第i句化不能由 mention 这些人 来讲
}
if (p < buf.size()) ++ p;
}
if (usr == "?") { //该名单暂定时
for (int j = 0 ; j <= n ; ++ j) { // j<=n 考虑第一个人这种特殊情况 ,遍历第i句话可以由哪些人说
if (!f[i][j]) continue; // 前一句话话如由j这个人说 .. 进行更新
for (int k = 0 ; k < n ; ++ k) { //则接下来只要这两个人不相邻,且不在黑名单中 就可以更新
if (mention.count(k) || k == j) continue;
f[i + 1][k] = 1;
g[i + 1][k] = j; // 记录该状态的转移
}
}
}
else {
if (!h.count(usr)) { // 不存在这个人
puts("Impossible");
return;
}
int id = h[usr]; //第id个人
if (!mention.count(id)) { //第id个人不在黑名单内
for (int j = 0 ; j <= n ; ++ j) { //更新当前这句话是由 id 这个讲的
if (f[i][j] && id != j) {
f[i + 1][id] = 1;
g[i + 1][id] = j;
}
}
}
}
}
int x = -1;
for (int i = 0 ; i < n ; ++ i) {
if (f[m][i]) {
x = i;
}
}
if (x == -1) {
puts("Impossible");
} else {
print(m , x);
}
}
int main() {
int T;
scanf("%d" , &T);
while (T --) {
work();
}
}