hdu4511 小明系列故事——女友的考验 [kuangbin专题-ac自动机]

这道题需要我们将路径表示成字符串形式,再构造fail指针。
需要注意的是开始位置是1号点,也就是ch[0][0],而不是根节点。当然如果给的路径中不含一号点,那可以理解成从根结点出发。
dp数组保存需要走的最长路径。

#include 
#include 
#include 
#include 
#include 
#include 
#define fi first
#define se second
#define FIN freopen("in.txt","r",stdin)
#define FIO freopen("out.txt","w",stdout)
#define INF 0x3f3f3f3f
#define per(i,a,n) for(int i = a;i < n;i++)
#define rep(i,a,n) for(int i = n;i > a;i--)
#define pern(i,a,n) for(int i = a;i <= n;i++)
#define repn(i,a,n) for(int i = n;i >= a;i--)
#define fastio std::ios::sync_with_stdio(false)
#define all(a) a.begin(), a.end()
#define ll long long
#define pb push_back
#define endl "\n"
#define pii pair
#define sc(n) scanf("%d", &n)
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
template<typename T> inline void _max(T &a,const T b){if(a<b) a = b;}
template<typename T> inline void _min(T &a,const T b){if(a>b) a = b;}
using namespace std;
//inline ll read(){
//    ll a=0;int f=0;char p=getchar();
//    while(!isdigit(p)){f|=p=='-';p=getchar();}
//    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();}
//    return f?-a:a;
//}

const int maxn = 600;

const int maxnode = 60;
const double inf = 1e18;

int ch[maxn][maxnode]; //字典树
int cnt[maxn];    //单词出现次数
int sz;
int fail[maxn];
char s[10];
int n,m;
double dp[600][600];
double x[60],y[60];
double dis(int a,int b)
{
    double tmp=sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
    //cout << tmp << endl;
    return tmp;
}
void init()
{

    sz = 1;
    memset(ch[0], 0, sizeof(ch[0]));
    memset(cnt,0,sizeof(cnt));
    //memset(dp,INF,sizeof(dp));
    cnt[0] = 0;

}

void insert(char str[], int len) //插入字符串
{
    int u = 0;
    per(i, 0, len)
    {
        int v = str[i];
        if (!ch[u][v])
        {
            memset(ch[sz], 0, sizeof(ch[sz]));
            cnt[sz] = 0;
            ch[u][v] = sz++;
        }
        u = ch[u][v];
    }
    cnt[u] = 1;


    //在这里我们可以建立一个int-string的映射,以通过节点序号得知这个点是哪个单词的结尾
}

void getfail()
{
    //所有模式串已插入完成
    queue<int> q;
    pern(i, 1,n)
    {
        if (ch[0][i])
        {
            fail[ch[0][i]] = 0;
            q.push(ch[0][i]);
        }
    }
    while (!q.empty())
    {
        int now = q.front();
        q.pop();
        pern(i, 1, n)
        {
            if (ch[now][i])
            {
                fail[ch[now][i]] = ch[fail[now]][i];
                q.push(ch[now][i]);
            }
            else
                ch[now][i] = ch[fail[now]][i];
        }
        cnt[now] |= cnt[fail[now]];
    }
}
void solve()
{
    for(int i=1;i<=n;i++)
        for(int j=0;j<sz;j++)
            dp[i][j]=inf;
    dp[1][ch[0][1]] = 0;
    pern(i,1,n)
    {
        per(j,0,sz)
        {
            if(dp[i][j]<inf)
            {
                pern(k,i+1,n)
                {
                    if(cnt[ch[j][k]] == 0)
                    {
                        dp[k][ch[j][k]] = min(dp[k][ch[j][k]],dp[i][j]+dis(i,k));
                    }
                }
            }
        }
    }
    double ans = inf;
    per(i,0,sz) ans = min(ans,dp[n][i]);
    if(ans >= inf)
        printf("Can not be reached!\n");
    else
        printf("%.2lf\n",ans);
}
int main()
{

    #ifndef ONLINE_JUDGE
        int startTime = clock();
        FIN;
    #endif
    //fastio;
	//忘记初始化是小狗
    //freopen("out.txt","w",stdout);
    //ios::sync_with_stdio(false);
    int k = 0,t;
    while(~scanf("%d%d",&n,&m))
    {
        if(n+m == 0) return 0;
        init();
        pern(i,1,n)
        {
            scanf("%lf%lf",&x[i],&y[i]);
        }
        per(i,0,m)
        {
            sc(k);
            per(j,0,k)
            {
                sc(t);
                s[j] = t;
            }
            s[k] = '\0';
            insert(s,k);
        }
        getfail();
        solve();
    }
    #ifndef ONLINE_JUDGE
        printf("\nTime = %dms\n", clock() - startTime);
    #endif
    return 0;
}

你可能感兴趣的:(ac自动机,字符串,算法竞赛相关,字符串)