题目来源:
2018年长沙理工大学ACM省赛选拔赛 2018年8月7日
题意:
dr所在国度的有个奇怪的规定:他们的字母不是a~z,而是用1~1000表示。
利用这个奇怪的规定,dr想出了一个好玩的游戏:首先给出n个字符串(当然每个字符用1~1000表示),然后给出有m个节点的树,节点编号1~m,这棵树以1号节点为根,每个节点都包含一个字符。现在要求用从根节点到其他m-1个节点的链上的字符组成m-1个新字符串(字符的排列顺序为从根到终点的顺序)。
是否这m-1个新字符串中的任意一个串,都与给出的n个字符串中至少一个串匹配呢?
字符串S与字符串T匹配:S是T的子串
输入:
第一行输入n和m,表示有n个字符串,树的节点数为m(
,
)
接下来n行,每行首先输入一个整数k,代表字符串长度,然后输入k个整数,代表字符串(
)
接下来一行,输入m个整数Ci,表示树上第i个节点上的字符
接下来m−1行,每行输入2个整数u,v(
,
),表示u和v有一条边
输出:
输出占一行,都能匹配输出YES,否则输出NO
题解:
字符串hash的入门题,我们用unorded_map记录hash值,树上套个简单的dfs就可以遍历整个树。
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <unordered_map>
#define INF 0x3f3f3f3f
#define SEED 131
using namespace std;
const int maxn = 200010;
unordered_map<unsigned long long, bool> hash_map;
unsigned long long hash_str, hash_tree[maxn];
int n, m, str_n, w[maxn], cnt, head[maxn];
struct Edge {
int to, next;
} edge[maxn];
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}
void addedge(int from, int to) {
edge[cnt].to = to;
edge[cnt].next = head[from];
head[from] = cnt++;
}
bool dfs(int u, int father) {
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (v == father)
continue;
hash_tree[v] = hash_tree[u] * SEED + w[v];
if (hash_map[hash_tree[v]] == false)
return false;
if (dfs(v, u) == false)//题意要求m-1中的任一个个串,所以只要有一个不满足就要返回false
return false;
}
return true;
}
int main(void) {
ios::sync_with_stdio(false);
init();
cin >> n >> m;
int temp, t1, t2;
for (int i = 1; i <= n; i++) {
cin >> str_n;
hash_str = 0;
for (int j = 1; j <= str_n; j++) {
cin >> temp;
hash_str = hash_str * SEED + temp;
hash_map[hash_str] = true;
}
}
for (int i = 1; i <= m; i++)
cin >> w[i];
for (int i = 1; i <= m - 1; i++)
cin >> t1 >> t2,addedge(t1, t2);
if (hash_map[w[1]] == false)
cout << "NO" << endl;
else {
hash_tree[1] = w[1];
if (dfs(1, 0))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}