题目链接: https://ac.nowcoder.com/acm/contest/5403/E
作为校赛的防ak题之一,可惜最后还是没人ac
将所有字符串(包括转化表中的字符串)插入到字典树中。对字符串s进行操作1相当于从字典树中s末尾代表的点向上走一步,操作2相当于从字典树中s末尾代表的点向下走一步(走到添加的字符代表的位置)。
转化表中的字符串可以互相转化,所以在字典树中添加连接任意两个转化表中字符串末尾代表的点的边。操作3就相当于在这些边上移动。
一般来说字典树是用0号点代表空串的,这里最好用1号点代表空串(否则之后跑最短路的时候就要把0号点也加入
在这个字典树改造出的图中,要把一个字符串a转化成字符串b就相当于从a末尾代表的点走到b末尾代表的点,最少操作次数自然就是最短路径。
现在询问转化为,图中有固定n个起点(n个字符串末尾代表的点)和1个移动点p,问p分别位于不同位置时,n个起点和p要移动到一起所需要走的最短路径和。
可以先对n个起点分别求出到图中所有点的最短路,n个起点到x点最短路加起来就是这n个起点移动到x点的最短路径和,记为sum[x]。若p和n个起点在x点汇合,则移动路径和就等于 p到x的最短路径 + sum[x]。
我们可以设定一个源点对每个点x连权值为sum[x]的边,然后求这个源点到全图的最短路,p位于i号点的答案就是源点到i号点的最短路径长度。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define maxn 100100
using namespace std;
int n, m, vis[maxn], dis[maxn], sum[maxn];
int lenA[45], lenB[45], tree[maxn][27], tot=1, posA[45][405], posB[45][405];
vector<int> edge[maxn];
string A[45], B[45];
void insert(string s, int pos[][405], int p)
{
int len=s.size(), rt=1, id;
for (int i=0; i<len; i++)
{
id=s[i]-'a';
if (!tree[rt][id])
{
tree[rt][id]=++tot;
edge[rt].push_back(tot);
edge[tot].push_back(rt);
}
rt=tree[rt][id];
pos[p][i]=rt;
}
}
void dijkstra(int s, int f)
{
priority_queue<pair<int, int> > pq;
if (f==0)
{
memset(dis, 127, sizeof(dis));
dis[s]=0;
pq.push(make_pair(0, s));
}
else
{
for (int i=1; i<=tot; i++)
{
dis[i]=sum[i];
pq.push(make_pair(-dis[i], i));
}
}
while (!pq.empty())
{
auto temp=pq.top(); pq.pop();
temp.first*=-1;
if (dis[temp.second]!=temp.first) continue;
for (auto i: edge[temp.second])
{
if (dis[i] > dis[temp.second]+1)
{
dis[i]=dis[temp.second]+1;
pq.push(make_pair(-dis[i], i));
}
}
}
}
int main()
{
cin>>n>>m;
for (int i=1; i<=n; i++)
{
cin>>A[i];
lenA[i]=A[i].size();
}
for (int i=1; i<=m; i++)
{
cin>>B[i];
lenB[i]=B[i].size();
}
for (int i=1; i<=n; i++)
insert(A[i], posA, i);
for (int i=1; i<=m; i++)
insert(B[i], posB, i);
for (int i=1; i<=m; i++)
for (int j=i+1; j<=m; j++)
{
edge[posB[i][lenB[i]-1]].push_back(posB[j][lenB[j]-1]);
edge[posB[j][lenB[j]-1]].push_back(posB[i][lenB[i]-1]);
}
for (int i=1; i<=n; i++)
{
dijkstra(posA[i][lenA[i]-1], 0);
for (int j=1; j<=tot; j++)
sum[j]+=dis[j];
}
dijkstra(0, 1);
for (int i=1; i<=n; i++)
{
for (int j=0; j<lenA[i]; j++)
cout<<dis[posA[i][j]]<<" ";
}
return 0;
}