hdu4511 小明系列故事——女友的考验(AC自动机+dp)

hdu4511

题目

中文题目

思路

AC自动机好久以前看的了,都要忘了。。。。正好复习以下。
dp[i][j] 表示在i点,状态在j的距离,转移比i大的点k,判断下一个状态ss是否可行,可行则转移到dp[k][ss]

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>

using namespace std;
const double INF = 1e20;
int n,m;

double dis(double x1,double y1,double x2,double y2)
{
    return sqrt((double)(1.0*x1-x2)*(1.0*x1-x2)+(double)(1.0*y1-y2)*(1.0*y1-y2));
}
double dp[55][1000];
double x[100],y[100];
int a[100];

struct Trie
{
    int next[1000][55],fail[1000],end[1000];
    int root,L;
    int newnode()
    {
        for(int i=1; i<=n; i++)
            next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }

    void init()
    {
        L=0;
        root=newnode();
    }

    void insert(int a[],int cnt)
    {
        int now=root;
        for(int i=0; i<cnt; i++)
        {
            if(next[now][a[i]]==-1)
                next[now][a[i]]=newnode();
            now=next[now][a[i]];
        }
        end[now]=1;
    }

    void build()
    {
        queue<int> q;
        fail[root]=root;
        for(int i=1; i<=n; i++)
        {
            if(next[root][i]==-1)
                next[root][i]=root;
            else
            {
                fail[next[root][i]]=root;
                q.push(next[root][i]);
            }
        }
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            end[now]|=end[fail[now]];
            for(int i=1; i<=n; i++)
                if(next[now][i]==-1)
                    next[now][i]=next[fail[now]][i];
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    q.push(next[now][i]);
                }
        }
    }


    void solve()
    {
        for(int i=1; i<=n; i++)
            for(int j=0; j<L; j++)
                dp[i][j]=INF;
        dp[1][next[root][1]]=0;
        for(int i=1; i<n; i++)
            for(int j=0; j<L; j++)
                if(dp[i][j]<INF)
                {
                    for(int k=i+1; k<=n; k++)
                    {
                        int ss=next[j][k];
                        if(end[ss]) continue;
                        dp[k][ss]=min(dp[k][ss],dp[i][j]+dis(x[i],y[i],x[k],y[k]));
                    }
                }

        double ans=INF;
        for(int i=0; i<L; i++)
            if(dp[n][i]<INF)
                ans=min(ans,dp[n][i]);
        if(ans == INF)printf("Can not be reached!\n");
        else printf("%.2f\n",ans);
    }
} ac;

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF&&(n+m))
    {
        for(int i=1; i<=n; i++)
            scanf("%lf%lf",&x[i],&y[i]);
        ac.init();
        int k;
        while(m--)
        {
            scanf("%d",&k);
            for(int i=0; i<k; i++)
                scanf("%d",&a[i]);
            ac.insert(a,k);
        }
        ac.build();
        ac.solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值