hdu 4511 小明系列故事——女友的考验

题目链接:点击打开链接

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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值