题目链接:点击打开链接
AC自动机上的最短路问题,题目要求所经过结点升序,且规定某些线路是不合法的,对应于AC自动机上的非法状态。
这道题目大部分题解是用DP来做的,而我是用Dijstra变形来解决这个题目的(同上篇文章)。做了好几天的AC自动机的习题,对于AC自动机还是有了一些理解,AC自动机在某个角度来看就是一张有特殊限制的图,每个结点代表不同状态,有不同的状态转移方程~~~~~
//AC自动机上跑最短路
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
const int MAXN=60;
const int MAXM=1000;
double dis[MAXN][MAXN];
pair<int,int> Point[MAXN];
struct node_t
{
node_t *son[60];
node_t *fail;
int num;
bool flag;
}Node[MAXM];
int toUsed;
inline void init_Trie()
{
toUsed=1;
memset(Node,0,sizeof(node_t));
}
inline node_t* _NewNode()
{
memset(Node+toUsed,0,sizeof(node_t));
Node[toUsed].num=toUsed;
return Node+toUsed++;
}
inline void insert(int K)
{
int T;
node_t *loc=Node;
for(int i=0;i<K;i++)
{
scanf("%d",&T);
if(!loc->son[T]) loc->son[T]=_NewNode();
loc=loc->son[T];
}
loc->flag=true;
}
void Build_AC(int N)
{
node_t *loc=Node;
loc->fail=NULL;
queue<node_t*> que;
for(int i=1;i<=N;i++)
{
if(loc->son[i])
{
loc->son[i]->fail=Node;
que.push(loc->son[i]);
}
}
while(!que.empty())
{
node_t *father=que.front();
if(father->fail->flag) father->flag=true;
que.pop();
for(int i=1;i<=N;i++)
{
node_t *p=father->son[i];
if(p)
{
node_t *v=father->fail;
while(v&&v->son[i]==NULL) v=v->fail;
if(v==NULL) p->fail=Node;
else p->fail=v->son[i];
que.push(p);
}
}
}
}
struct info
{
node_t *loc;
int cur;
double dis;
info(int _cur=0,node_t *_loc=NULL,double _dis=0) {cur=_cur;loc=_loc;dis=_dis;}
bool operator < (const info& r)const {return dis>r.dis;}
};
node_t *linker[MAXM][MAXN];
double disk[MAXN][MAXM];
void bfs(int N)
{
for(int i=0;i<=N;i++)
for(int j=0;j<=toUsed;j++)
disk[i][j]=1e20;
priority_queue<info> que;
while(!que.empty()) que.pop();
if(Node->son[1]) {que.push(info(1,Node->son[1],0));disk[1][Node->son[1]->num]=0;}
else {que.push(info(1,Node,0));disk[1][Node->num]=0;}
while(!que.empty())
{
info tmp=que.top();
que.pop();
int u=tmp.cur;
if(u==N)
{
printf("%.2lf\n",tmp.dis);
return;
}
for(int i=u+1;i<=N;i++)
{
node_t *loc=linker[tmp.loc->num][i];
if(loc->flag) continue;
if(disk[i][loc->num]>disk[u][tmp.loc->num]+dis[u][i])
{
disk[i][loc->num]=disk[u][tmp.loc->num]+dis[u][i];
que.push(info(i,loc,disk[i][loc->num]));
}
}
}
printf("Can not be reached!\n");
}
inline double dist(int i,int j)
{
double disx=1.0*Point[i].first-Point[j].first,disy=1.0*Point[i].second-Point[j].second;
return sqrt((double)(1.0*disx*disx)+double(1.0*disy*disy));
}
int main()
{
int N,M,K,T;
while(scanf("%d%d",&N,&M)&&(N||M))
{
init_Trie();
for(int i=1;i<=N;i++)
scanf("%d%d",&Point[i].first,&Point[i].second);
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++)
dis[i][j]=dis[j][i]=dist(i,j);
for(int i=1;i<=M;i++)
{
scanf("%d",&K);
insert(K);
}
Build_AC(N);
for(int i=0;i<toUsed;i++)
for(int j=1;j<=N;j++)
{
node_t *loc=Node+i;
while(loc&&loc->son[j]==NULL) loc=loc->fail;
loc=loc?loc->son[j]:Node;
linker[i][j]=loc;
}
bfs(N);
}
return 0;
}