【HDU 4511】小明系列故事——女友的考验(AC自动机+DP)

Problem Description

  终于放寒假了,小明要和女朋友一起去看电影。这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则:
  1、假设小明在的位置是1号点,女朋友在的位置是n号点,则他们之间有n-2个点可以走,小明每次走的时候只能走到比当前所在点编号大的位置;
  2、小明来的时候不能按一定的顺序经过某些地方。比如,如果女朋友告诉小明不能经过1 -> 2 -> 3,那么就要求小明来的时候走过的路径不能包含有1 -> 2 -> 3这部分,但是1 -> 3 或者1 -> 2都是可以的,这样的限制路径可能有多条。
  这让小明非常头痛,现在他把问题交给了你。
  特别说明,如果1 2 3这三个点共线,但是小明是直接从1到3然后再从3继续,那么此种情况是不认为小明经过了2这个点的。
  现在,小明即想走最短的路尽快见到女朋友,又不想打破女朋友的规定,你能帮助小明解决这个问题吗?

Input

  输入包含多组样例,每组样例首先包含两个整数n和m,其中n代表有n个点,小明在1号点,女朋友在n号点,m代表小明的女朋友有m个要求;
  接下来n行每行输入2个整数x 和y(x和y均在int范围),代表这n个点的位置(点的编号从1到n);
  再接着是m个要求,每个要求2行,首先一行是一个k,表示这个要求和k个点有关,然后是顺序给出的k个点编号,代表小明不能走k1 -> k2 -> k3 ……-> ki这个顺序的路径;
  n 和 m等于0的时候输入结束。

  [Technical Specification]
  2 <= n <= 50
  1 <= m <= 100
  2 <= k <= 5

Output

  对于每个样例,如果存在满足要求的最短路径,请输出这个最短路径,结果保留两位小数;否则,请输出”Can not be reached!” (引号不用输出)。

【题目大意】n个点,从1~n,每次只能走序号比之前序号大的,并且不能出现规定的顺序,求1~n的最短路径

【解题思路】

规定的顺序可以看作AC自动机上的字符串,从一个节点到另外一个节点

因为如果上面的路径没有办法到达的话,就说明下面的路径也没有办法到达

之后,用dp去求

dp[ i ] [ j ]  表示现在位置在第 i 个节点同时已经走到了AC自动机上的节点 j ,即已经经过了对应的路径

然后枚举状态转移

dp [ k ] [ t r i e [ j ] [ k ] ]   =   m i n ( d p [ k ] [ t r i e [ j ] [ k ] ] ,   d p [ i ] [ j ]   +   d i s ( i ,   k ) )

从点 i 走到点 k ,AC自动机的节点从 j 到 k ,距离增加 dis( i ,j )

【注意】

数组的类型定义错误,改了一个小时QAQ

本来应该定义成double ,结果定义成了 i n t ,nmd

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int     MAXN = 6000;
const int     MAXM = 600;
const double  INF  = 1e18;
int     trie[600][60],cnt;
int     fail[600],val[600],n,m,k;
double  dp[60][600];
struct node
{
    double x, y;
}a[60];
void insert(double *v)
{
    int now = 0;
    for (int i = 1; i <=k; i++)
    {
        int u = v[i];
        if (!trie[now][u])
        {
            trie[now][u] = ++cnt;
        }
        now = trie[now][u];
    }
    val[now]=1;
}
void get_fail()
{
    int now = 0;
    queue<int> q;
    for (int i = 1; i <=n; i++)
        if (trie[now][i])
        {
            fail[trie[now][i]] = 0;
            q.push(trie[now][i]);
        }
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        if (val[fail[u]])
            val[u]=1;
        for (int i = 1; i <=n; i++)
        {
            int v = trie[u][i];
            if (v)
            {
                fail[v] = trie[fail[u]][i];
                q.push(v);
            }
            else
            {
                trie[u][i] = trie[fail[u]][i];
            }
        }
    }
    return;
}
double dis(int i, int j)
{
    double tmp = (a[i].x - a[j].x)*(a[i].x - a[j].x) + (a[i].y - a[j].y)*(a[i].y - a[j].y);
    return sqrt(tmp);
}
double v[600];
double solve()
{
    double minn = INF;
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= cnt; j++)
            dp[i][j] = INF;
    dp[1][trie[0][1]] = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j <= cnt; j++)
        {
            if (dp[i][j]<INF)
            {
                for (int k = i + 1; k <= n; k++)
                    if (!val[trie[j][k]])
                        dp[k][trie[j][k]] = min(dp[k][trie[j][k]], dp[i][j] + dis(i, k));
            }
        }
    }
    for(int i=0;i<=cnt;i++)
            minn = min(minn, dp[n][i]);
    return minn;
}
int main()
{
    while (scanf("%d%d", &n, &m) && n && m)
    {
        cnt = 0;
        memset(trie, 0, sizeof(trie));
        memset(val, 0, sizeof(val));
        memset(fail, 0, sizeof(fail));
        for (int i = 1; i <= n; i++)
            scanf("%lf%lf", &a[i].x, &a[i].y);
        while(m--)
        {

            scanf("%d", &k);
            for (int i = 1; i <= k; i++)
                scanf("%lf", &v[i]);
            insert(v);
        }
        get_fail();
        double ans = solve();
        if (ans >= INF)
            printf("Can not be reached!\n");
        else
            printf("%.2f\n", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/rentu/p/11336071.html

时间: 2024-11-07 23:52:09

【HDU 4511】小明系列故事——女友的考验(AC自动机+DP)的相关文章

HDU - 4511 小明系列故事――女友的考验(AC自动机+DP)

Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则: 1.假设小明在的位置是1号点,女朋友在的位置是n号点,则他们之间有n-2个点可以走,小明每次走的时候只能走到比当前所在点编号大的位置: 2.小明来的时候不能按一定的顺序经过某些地方.比如,如果女朋友告诉小明不能经过1 -> 2 -> 3,那么就要求小明来的时候走过的路径不能包含有1 -> 2 ->

HDU ACM 4511 小明系列故事——女友的考验-&gt;AC自动机+DP

分析:参考别人的搞. 1.AC自动机: 使用AC自动机来压缩路段,如禁掉的路段是1->2->3,那么插入字符串(123) ,注意点只有1~50,所以0~50用ASCII 压缩成字符串即可. 这样就能够完成禁止路段的在线状态转移. 2.DP部分: 两点之间的最短路.dp[i][j]表示在地点i,当前字符是j的状态. 初始化:fill(&dp0][0],&dp[maxn-1][maxp-1],inf),inf=1e12,memset不能用. 边界:首先找出出发点在Pool中的位置,

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

小明系列故事——女友的考验 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 822    Accepted Submission(s): 176 Problem Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则

HDU 4511 小明系列故事——女友的考验 (AC自动机+DP)

小明系列故事--女友的考验 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1734    Accepted Submission(s): 466 Problem Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规

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

小明系列故事--女友的考验 Time Limit: 500/200 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 863 Accepted Submission(s): 192 Problem Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则: 1.假

AC自动机 + 二维最短路 HDU 4511 小明系列故事――女友的考验

这个题还是比较好想的. 首先将所有不可行方案建立AC自动机,然后跑最短路. 首先将小明放在(sta = 0,pos = 0)处,sta表示AC自动机上点的编号,pos表示坐标点的编号. 根据pos枚举下一次可以到达的地方[pos+1,n],然后sta在自动机上移动,如果某一步会使sta位于有标记的节点,那么这一步是不可行. #include <iostream> #include<time.h> #include<stdio.h> #include<string.

HDU 4511 小明系列故事——女友的考验 (AC自动机 + DP)题解

题意:从 1 走到 n,要求所走路径不能出现给定的路径,求最短路 思路:因为要求不能出现给定路径,那么我可以求助ac自动机完成判断. 我们可以在build的时候标记哪些路径不能出现,显然下面这种表示后缀不能出现,那么他也不能出现 if(node[node[u].fail].cnt && u) node[u].cnt = 1; //都不能取 然后再把图建完整.因为如果一个路径不在Trie中有两种情况,一种是他可能是某个不能走的串的前缀,那么我就重新指向这个不能走的串,比如Trie中只有AT,

hdu4511小明系列故事——女友的考验(ac自动机+最短路)

链接 预处理出来任意两点的距离,然后可以顺着trie树中的节点走,不能走到不合法的地方,另开一维表示走到了哪里,依次来更新. 注意判断一下起点是不是合法. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmat

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

题目大概说有平面有n个点,从1点出发走到n点,每一步只能走到序号比当前更大的点且走的序列不能包含给定的m个序列中的任何一个,问1走到n的最短路. 用m个序列建个AC自动机,后缀包含整个序列的结点标记一下,然后用dp[u][S]表示走到u点且走的序列的后缀状态是自动机上第S个结点的最短路,这样在AC自动机上跑着转移就OK了. 1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<que