[一本通1683]稗田阿求
题目描述
在幻想乡,稗田乙女是负责书写《幻想乡缘起》的家族。由于需要代代相传关于幻想乡的记忆,稗田乙女采用了一些特殊的记录方式。对于相同重复的文字,稗田乙女会用一个数字来代替,然后用一个数列来表示一个段文字。比如 \(1\)代表“\(A\)”,\(2\)代表“\(C\)”,那么\(\{1,2\}\)就代表“\(AC\)”,\(\{2,1,2\}\)就代表“\(CAC\)”。不过由于年代过于久远,到阿求时已经是第九代稗田乙女,所以难免会出现错误。现在阿求有\(N\)个数字\((1..N)\)和\(N\)个字符(“\(A\)”..第\(N\)个字母),以及一些以前传承下来的M组文字段和对应的数列。每一组文字段和数列相互对应,文字的第\(i\)个字符对应着数列的第\(i\)项。阿求想要知道怎样安排\(N\) 个数字和字符的对应关系,能够使组数尽可能多的文字段和数列组合满足该对应关系。数字和字符间一一对应,不会出现多对一或一对多的情况。
输入
第1行:\(2\)个正整数\(N, M\)。
第\(2..2M+1\)行:每\(2\)行为一组,第\(1\)行为文字段落,第\(2\)行为数列。保证文字段落的字符数\(L\)等于数列数字个数\(L\),且均在\(1..N\)。文字段落只包含大写字母。
输出
第1行:最多能够匹配的文字段落和数列组合数量。
输入样例
3 3
ACCA
1 3 3 1
AAC
2 2 1
BCBC
3 1 3 1
输出样例
2
提示
样例解释
当\(A=2,B=3,C=1\)时第\(2、3\)字符串和数列组合满足对应关系。
数据规模
对于60%的数据:\(1≤N≤10,1≤M≤20\)。
对于100%的数据:\(1≤N≤26,1≤M≤40,1≤L≤100\)。
注意事项
保证每一组文字段和数列组合均合法,在一组文字段和数列组合里面不会出现多个字符对一个数字,或是一个字符对多个数字的情况。
思路
本题的数据比较小,首先初始化好每个文本的不同字符对应的数字的情况。
然后枚举两两配对的情况,并且用状态压缩存起来。
其中有个可以优化的地方,当检测到之后的完全都可匹配上也没有最优解好时,可以直接退出。
代码
话不多说,直接上代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char str[128];
int n, m;
int view[45][28]; //字符串中字母对应的数字
bool vis[28]; //标记被占用的字母
unsigned long long mate[45]; //状态压缩表示相容的字符串编号
int ans = 0;
inline bool AStar(int u, int cnt) //判断最好情况下能否超越当前最优解
{
return cnt + m - u + 1 >= ans;
}
void dfs(int u = 1, int cnt = 0, unsigned long long st = -1LL)
{
if (!AStar(u, cnt))
return; //无论如果都无法超越当前最优解
if (u > m)
{
ans = max(ans, cnt);
return;
}
if (st & 1LLU << (u - 1)) //相容
dfs(u + 1, cnt + 1, st & mate[u]); //收录
dfs(u + 1, cnt, st); //不收录
}
int main()
{
scanf(" %d %d", &n, &m);
for (int i = 1; i <= m; i++)
{
scanf(" %s", str + 1);
for (int j = 1; str[j] != 0; j++)
{
scanf(" %d", &view[i][str[j] - 'A']);
}
}
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++)
if (i != j)
{
for (int k = 0; k < 26; k++)
if (view[i][k] && view[j][k] && view[i][k] != view[j][k])
{
goto End;
}
memset(vis, 0, sizeof(vis));
for (int k = 0; k < 26; k++)
if (view[i][k] || view[j][k])
{
int t;
if (!view[i][k])
t = view[j][k];
else
t = view[i][k];
if (!vis[t])
vis[t] = true;
else //之前有字母占用了
{
goto End;
}
}
mate[i] |= 1LLU << (j - 1);
End:;
}
dfs();
printf("%d", ans);
return 0;
}