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


    题目链接:https://vjudge.net/problem/HDU-4511

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

    Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
    Total Submission(s): 1924    Accepted Submission(s): 525


    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!” (引号不用输出)。
     
    Sample Input
    3 1 1 1 2 1 3 1 2 1 2 2 1 0 0 1 1 2 1 2 5 3 0 0 5 3 1 2 1 22 5 21 3 1 2 3 2 4 5 2 1 5 0 0
     
    Sample Output
    2.00 Can not be reached! 21.65
     
    Source

    题意:

    有n个点(1~n)且已知每个点的坐标。求点1走到点n的最短路径,要求路径上点的标号递增,并且不能走给出的m条禁止路线。

    题解:

    1.将m条进制路线插入AC自动机中。

    2.设dp[i][j]为:当前点为i,且到达的状态为j(自动机上的状态)的最短路径(从点1到点i)。

    3.由于题目规定了“路径上点的标号递增”,那么可以直接递推求解:dp[k][newj] = min(dp[k][newj], dp[i][j]+dis(i,k)),其中 i+1<=k<=n,newj为下一个状态。

    代码如下:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <cmath>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <string>
     11 #include <set>
     12 using namespace std;
     13 typedef long long LL;
     14 const double EPS = 1e-6;
     15 const int INF = 2e9;
     16 const LL LNF = 2e18;
     17 const int MOD = 1e5;
     18 const int MAXN = 1e3+10;
     19 
     20 double x[55], y[55],  dp[MAXN][MAXN];
     21 
     22 double dis(int i, int j)
     23 {
     24     return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
     25 }
     26 
     27 struct Trie
     28 {
     29     int sz, base;
     30     int next[MAXN][55], fail[MAXN], end[MAXN];
     31     int root, L;
     32     int newnode()
     33     {
     34         for(int i = 0; i<sz; i++)
     35             next[L][i] = -1;
     36         end[L++] = false;
     37         return L-1;
     38     }
     39     void init(int _sz, int _base)
     40     {
     41         sz = _sz;
     42         base = _base;
     43         L = 0;
     44         root = newnode();
     45     }
     46     void insert(int buf[], int len)
     47     {
     48         int now = root;
     49         for(int i = 0; i<len; i++)
     50         {
     51             if(next[now][buf[i]-base] == -1) next[now][buf[i]-base] = newnode();
     52             now = next[now][buf[i]-base];
     53         }
     54         end[now] |= true;
     55     }
     56     void build()
     57     {
     58         queue<int>Q;
     59         fail[root] = root;
     60         for(int i = 0; i<sz; i++)
     61         {
     62             if(next[root][i] == -1) next[root][i] = root;
     63             else fail[next[root][i]] = root, Q.push(next[root][i]);
     64         }
     65         while(!Q.empty())
     66         {
     67             int now = Q.front();
     68             Q.pop();
     69             end[now] |= end[fail[now]];
     70             for(int i = 0; i<sz; i++)
     71             {
     72                 if(next[now][i] == -1) next[now][i] = next[fail[now]][i];
     73                 else fail[next[now][i]] = next[fail[now]][i], Q.push(next[now][i]);
     74             }
     75         }
     76     }
     77 
     78     double query(int n)
     79     {
     80         for(int i = 1; i<=n; i++)
     81         for(int j = 0; j<L; j++)
     82             dp[i][j] = LNF;
     83 
     84         dp[1][next[root][1-base]] = 0;  //注意,其实状态不是root,而是next[root][1-base],因为从点1开始。
     85         for(int i = 1; i<n; i++)
     86         for(int j = 0; j<L; j++)
     87         {
     88             if(end[j] || dp[i][j]>=LNF) continue;
     89             for(int k = i+1; k<=n; k++)
     90             {
     91                 int newj = next[j][k-base];
     92                 if(end[newj]) continue;
     93                 dp[k][newj] = min(dp[k][newj], dp[i][j]+dis(i,k));
     94             }
     95         }
     96         double ret = LNF;
     97         for(int i = 0; i<L; i++)
     98             ret = min(ret, dp[n][i]);
     99         return ret;
    100     }
    101 };
    102 
    103 Trie ac;
    104 int buf[MAXN];
    105 int main()
    106 {
    107     int n, m, k;
    108     while(scanf("%d%d", &n,&m) && (n||m))
    109     {
    110         ac.init(n,1);
    111         for(int i = 1; i<=n; i++)
    112             scanf("%lf%lf", &x[i], &y[i]);
    113         while(m--)
    114         {
    115             scanf("%d", &k);
    116             for(int i = 0; i<k; i++)
    117                 scanf("%d", &buf[i]);
    118             ac.insert(buf, k);
    119         }
    120 
    121         ac.build();
    122         double ans = ac.query(n);
    123         if(ans>=LNF) printf("Can not be reached!
    ");
    124         else printf("%.2f
    ", ans);
    125     }
    126     return 0;
    127 }
    View Code
  • 相关阅读:
    解决mysql错误1130的方法(远程出错)
    取消pve无效订阅弹窗命令
    测试环境主机执行脚本
    OpenStack Ocata版本安装
    OpenStack简介
    JVM内存分配及调优方案(基于JDK1.8)
    大数据之数据仓库
    clickhouse核心引擎MergeTree子引擎
    clickhouse高可用-节点宕机数据一致性方案-热扩容
    Clickhouse集群部署
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8456700.html
Copyright © 2020-2023  润新知