题目背景
小明最近上课天天睡觉,于是啥都不会。
一天,老师终于点兵点将点到他回答问题,你能帮他渡过难关吗?
现在老师给了小明 n 个由 0、1 构成的字符串,然后有 m 次询问,
每次询问给出一个由 0、1 构成的字符串,
小明需要在最开始的 n 个字符串中找出和当前字符串匹配的前缀最长的串。
如果有多个前缀最长的串,请找出字典序最小的那个。
如果小明找不出来,小明就无了,你能帮助小明吗?
输入格式:
输入第一行是一个整数 t ,表示有 t 组测试实例。
对于每组输入:
输入第一行包含一个整数 n ,代表接下来有 n 行。
接下来 n 行,每行1个字符串,字符串只由0、1构成。
接下来这一行有一个整数 m ,表示询问次数。
接下来 m 行,每行1个字符串,字符串只由0、1构成。
对于每一次询问,你需要求出匹配的前缀最长的字符串,如果有多个答案,请输出字典序最小的那个。
输出格式:
对于每组输入:
输出共 m 行,每行一个字符串对应询问的答案。
输入样例:
2
5
0100
0101
011
10110
10111
1
10011011
4
01
1001
1011100
00110
2
100011
01100
输出样例:
10110
1001
01
先上超时代码(14分)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
vector<string>v;
int N, t;
string str;
void sove()
{
v.clear();
cin >> N;
while (N--)
{
cin >> str;
v.emplace_back(str);
}
sort(v.begin(), v.end());
cin >> N;
while (N--)
{
cin >> str;
int res = 0;
string ch ;
ch += str[0];
auto it = lower_bound(v.begin(), v.end(), ch);
string ans = v[(int)(it - v.begin())];
int pos = (int)(it - v.begin());
for (int i = pos; i < v.size(); i++)
{
int len = 0;
for(int j = 0;j < v[i].size();j++)
if(str[j] == v[i][j])len++;
else break;
if(len >= res)
{
if(len > res)res = len,ans = v[i];
else
ans = min(ans,v[i]);
}
else break;
}
cout << ans << endl;
}
}
int main()
{
cout.tie(0);
cin.tie(0)->sync_with_stdio(false);
cin >> t;
while (t--)
sove();
return 0;
}
如何解决?>>01树(本质就是字典树,算是字典树的特殊情况,即树中元素均为0或1)
受不了这个模拟(有点麻烦讲真的)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxn = 500 + 10;
int n, t, m;
bool is = true;
string str;
struct Tree
{
char ch;
bool flag;
Tree* L, * R;
Tree(char c) :ch(c), L(NULL), R(NULL), flag(false) {};
};
Tree* Built_01Tree(Tree* root, string str, int w)
{
if(str.size() == 1)
{
if(str[w] == '1'&& !root -> L)
{
root -> L = new Tree('1');
root -> L -> flag = true;
}
else if(str[w] == '0' && !root -> R)
{
root -> R = new Tree('0');
root -> R -> flag = true;
}
else
{
str[w] == '1' ? root -> L -> flag = true : root -> R -> flag = true;
}
return root;
}
if (w == str.size())return NULL;
if (!root)
root = new Tree(str[w]);
if (w == str.size() - 1) root -> flag = true;
else if (root->ch == str[w] && w + 1 <= str.size())
str[w + 1] == '1' ? root->L = Built_01Tree(root->L, str, w + 1) : root->R = Built_01Tree(root->R, str, w + 1);
else if (root->ch != str[w] && w + 1 <= str.size())
str[w] == '1' ? root->L = Built_01Tree(root->L, str, w) : root->R = Built_01Tree(root->R, str, w);
return root;
}
string Find(Tree* root, string str, int w)
{
string ans;
if (!root)return ans;
ans += root -> ch;
if(is)
{
if(w >= str.size() && root -> flag)return ans;
if(root -> flag && !is) return ans;
if(root -> flag && w == str.size())return ans;
if(root -> R && root -> R -> ch == str[w])ans += Find(root -> R,str,w + 1);
else if(root -> L && root -> L -> ch == str[w])ans += Find(root -> L,str,w + 1);
else
{
is = false;
if(root -> flag)return ans;
root -> R ? ans += Find(root -> R,str,w + 1) : ans += Find(root -> L,str,w + 1);
}
}
else
{
if(root -> flag)return ans;
//if(root -> flag && w == str.size())return ans;
root -> R ? ans += Find(root -> R,str,w + 1) : ans += Find(root -> L ,str,w + 1);
}
return ans;
};
void pre_cout(Tree* root)
{
if (!root)return;
cout << root->ch;// << " ";
pre_cout(root->L);
pre_cout(root->R);
}
void solve()
{
cin >> n;
Tree* root = new Tree('H');
while (n--)
{
cin >> str;
// cout << str << endl;
Built_01Tree(root, str, 0);
}
// pre_cout(root);
// cout << endl;
cin >> n;
while (n--)
{
cin >> str;
is = true;
string ans = Find(root, str, 0);
ans.erase(0, 1);
cout << ans << endl;
}
}
int main()
{
IOS
cin >> t;
while (t--)
solve();
return 0;
}
// //H101110011010
// //H101110001010110
其中:对于答案的求法:情况如下:
1: 如果有当前前缀可以匹配则继续向下搜索
2 : 如果当前前缀无法匹配且改结点是一个01串的终点,结束搜索返回答案
3:如果当前前缀无法匹配但是改结点不是01串终点,根据输出字典序最小的,先访问0结点位置是否存在,存在向0方向搜索,反之向1方向搜索
将测试代码剔除后,有效代码如下:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
int n, t, m;
bool is = true;
string str;
struct Tree
{
char ch;
bool flag;
Tree* L, * R;
Tree(char c) :ch(c), L(NULL), R(NULL), flag(false) {};
};
Tree* Built_01Tree(Tree* root, string str, int w)
{
if(str.size() == 1)
{
if(str[w] == '1'&& !root -> L)
{
root -> L = new Tree('1');
root -> L -> flag = true;
}
else if(str[w] == '0' && !root -> R)
{
root -> R = new Tree('0');
root -> R -> flag = true;
}
else
str[w] == '1' ? root -> L -> flag = true : root -> R -> flag = true;
return root;
}
if (!root)
root = new Tree(str[w]);
if (w == str.size() - 1) root -> flag = true;
else if (root->ch == str[w] && w + 1 <= str.size())
str[w + 1] == '1' ? root->L = Built_01Tree(root->L, str, w + 1) : root->R = Built_01Tree(root->R, str, w + 1);
else if (root->ch != str[w] && w + 1 <= str.size())
str[w] == '1' ? root->L = Built_01Tree(root->L, str, w) : root->R = Built_01Tree(root->R, str, w);
return root;
}
string Find(Tree* root, string str, int w)
{
string ans;
if (!root)return ans;
ans += root -> ch;
if(is)
{
if(w >= str.size() && root -> flag)return ans;
if(root -> R && root -> R -> ch == str[w])ans += Find(root -> R,str,w + 1);
else if(root -> L && root -> L -> ch == str[w])ans += Find(root -> L,str,w + 1);
else
{
is = false;
if(root -> flag)return ans;
root -> R ? ans += Find(root -> R,str,w + 1) : ans += Find(root -> L,str,w + 1);
}
}
else
{
if(root -> flag)return ans;
root -> R ? ans += Find(root -> R,str,w + 1) : ans += Find(root -> L ,str,w + 1);
}
return ans;
};
void solve()
{
cin >> n;
Tree* root = new Tree('H');
while (n--)
{
cin >> str;
Built_01Tree(root, str, 0);
}
cin >> n;
while (n--)
{
cin >> str;
is = true;
string ans = Find(root, str, 0);
ans.erase(0, 1);
cout << ans << endl;
}
}
int main()
{
cin.tie(0) -> sync_with_stdio(false);
cin >> t;
while (t--) solve();
return 0;
}